views:

120

answers:

8

EDIT:That was fast. The reason why I have this is because the table is a pivot table between 2 tables one has "id" as primary key and the other "type" primary key

Hello.

I want the following:

Find only find "id" where "type" is 1 AND 2 AND 3

This is not working:

SELECT * FROM `table` WHERE `type` = 1 AND `type` = 2 AND `type` = 3;

The SELECT statment should only return one row (id = 1)

Table

id type
1  1
1  2
1  3

2  1
2  2

3  3
A: 

If I understand you correctly, couldn't you just add LIMIT 1 at the end of your query?

girasquid
Cannot because you need to match all where clauses, which is impossible with a single select.
Kevin Peno
A: 

You're doing something wrong. You should not have multiple rows with the same id. It destroys the point of having one. Your id column should be a primary key that auto increments.

I think you should go back and reexamine your schema. Or at least add more detail about what you're trying to do.

Tyler Smith
How can you make a comment about his schema without knowing the implementation?
Kevin Peno
Kevin, are you sure that you do understand what is written in the original question? No matter how does he produce this table, his select tries to evaluate predicate type=1 AND type=2 AND type=3 for a single row with a single value of type.
Dmitry
Check the DATA supplied in the question and see my answer. I fully understand the question ;)
Kevin Peno
Kevin, I am commenting on his schema because he has an id column with repeating values. That breaks the entire point of an id column.Edit: And his edit clarifies what he's doing. My post was made believing that id should be a primary key (which, frankly, it should be, and then he should have another column foo_id).
Tyler Smith
No, you are assuming that the id column is the only primary key value. You are also not taking into count the possibility of having an intersect table (which is likely what this is) which could/would have the exact format of data as shown in his example.
Kevin Peno
In the supplied data there is exactly one type value in every row. This predicate will be false for any row in his data. What he *wants* is a different question (yes, I understand now that he wants those ids which have all types in different rows), but he definitely is trying to do a *wrong* thing
Dmitry
You are so stuck on the WHERE. He used the WHERE because that's what he knows. Obviously it doesn't work or he wouldn't have asked "how can I do this". The question is the same regardless.
Kevin Peno
We're trying to help him to understand his problem, right? He is doing a very wrong thing, so he definitely should know why it is wrong. You instead is focused on his problem -- that's ok, but why are you downvoting those who is explaining why his code doesn't work?
Dmitry
+2  A: 

A row can't have a column with a value 1 AND 2 AND 3 at the same time. It's like asking you if you're "20 and 21 and 22 years old". You can only be one of them.

You'd want to do something akin to:

SELECT id WHERE type = 1
INTERSECT
SELECT id WHERE type = 2
INTERSECT
SELECT id WHERE type = 3

but MySQL doesn't support INTERSECT, so you have to do it by hand:

SELECT id FROM table WHERE
    id IN (SELECT id FROM table WHERE
             id IN (SELECT id FROM table WHERE type = 3)
             AND type = 2)
    AND type = 1
Tordek
Interesting subselect...I wouldn't go that route, but it should work.
Kevin Peno
I won't deny that it's ugly-ish... but it's 3 queries where the top voted solution has O(n^2) queries (which could be optimized, but I wouldn't bet on it).
Tordek
True enough. The beauty of the top post is that it doesn't continue to nest. In the case of your own, what happens if there are 5 types to match? 10? What I will give you though is that your query will always use indexes...which is why I like it :P
Kevin Peno
+1  A: 

Your search conditions are incompatible. Field 'type' can't be at the same time equal to 1, 2 and 3. Given the absence of INTERSECT in MySQL, you can join the same table two times:

SELECT id FROM 
  Table t1 JOIN Table t2 ON (t1.id=t2.id) JOIN Table t3 ON (t3.id=t2.id)
WHERE t1.type=1 AND t2.type=2 AND t3.type=3

This will build a cartesian product of rows with the same id and retain only those which have all three types you want.

Learning the basics of SQL can help you a lot. There is a lot of information around. (including MySQL docs)

Dmitry
Learning advanced SQL might help you as well ;) Subselects make this more than possible, among other things.
Kevin Peno
Can you please point me to a table where this condition type=1 AND type=2 ANd type=3 can be true? Thanks.
Dmitry
It cannot for a single row, but it can across multiple rows (as is the case in his data) where an identifier is common. You see this sort of intersecting a lot with tags. One would have a "post/article" table and then have a table of tags tied to that post. There would only be ONE article ID, but many tags IDs in the intesecting table. Thus you end up with a requirement like this.
Kevin Peno
Do you understand that select evaluates a predicate written in WHERE clause for a single row? It will always be false, unless something has recently changed in the relational model and first normal form.
Dmitry
His data isn't "wrong", which is why I've downvoted those saying it is. He even edited his question verifying so. ;)
Kevin Peno
fupsduck's answer says nothing about data. He pointed to a wrong query.
Dmitry
And his answer doesn't answer the question. Downvoting is for bad answers. The answer is bad. fupsduck simply stated the obvious...his query won't work. That's not the question. The question is (and was "How can I perform a select that will return the result I want...{this query} isn't working".
Kevin Peno
Kevin, there was no question at all. So everyone was free to guess what was the question -- "Why it doesn't work?" or "How can I get the result I want?"
Dmitry
`Hello. I want the following: Find only "id" where "type" is 1 AND 2 AND 3`. How is that not a question?
Kevin Peno
No. It is a statement. I can interpret it as "why my code doesn't do it?"
Dmitry
+1 to both of you for your passion.
fupsduck
+5  A: 

If you only want to know the Id then add the keyword Distinct and just select the id, where there are records for the three different types ...

  Select Distinct id 
  FROM `table` t
  WHERE  Exists (Select * From Table Where id = t.id and Type = '1')
     And Exists (Select * From Table Where id = t.id and Type = '2')
     And Exists (Select * From Table Where id = t.id and Type = '3')

If you want to see the Id and the type then add the type to the select,

 Select Distinct id, Type 
  FROM `table` t
  WHERE  Exists (Select * From Table Where id = t.id and Type = '1')
     And Exists (Select * From Table Where id = t.id and Type = '2')
     And Exists (Select * From Table Where id = t.id and Type = '3')

if you want to see every row that has that id, then leave out the distinct

  Select id, Type 
  FROM `table` t
  WHERE  Exists (Select * From Table Where id = t.id and Type = '1')
     And Exists (Select * From Table Where id = t.id and Type = '2')
     And Exists (Select * From Table Where id = t.id and Type = '3')
Charles Bretana
A: 

Your selecting for the impossible. For each row, type can not be three things at once.

fupsduck
No, but you CAN subquery.
Kevin Peno
Kevin - please explain how for a given row in a database a field can simultaneously have three different values?
fupsduck
One cannot, many with one common ancestor can. See my comment on Dmitry's answer for a real world case.
Kevin Peno
Kevin - I think you simply missed the point some of us were trying to make that the asker did not understand - that as initially stated his SELECT statement could never return a row.
fupsduck
That's why he asked "How can I get the result I want". If you wanted an up vote, you would have answered the question instead of stating the obvious and moving on. ;)
Kevin Peno
He didn't ask anything. There is no "?" in his message even at the moment of writing this.
Dmitry
I was simply offering the asker some insight, which was not at all obvious to the asker, not a solution - this process is collaborative.
fupsduck
Dmitry, you should really stop cross posting. @fupsduck: I understand where you are coming from, but like Dmitry you missed the question that was there (read my post to Dmitry if you need it called out exactly as the author wrote it) and your insight was incorrect, as it is NOT impossible when done through subqueries. It is ok if you do not agree with my assessment, but it is my assessment. And, as you said, this is a collaborative site/effort. :)
Kevin Peno
His insight was correct. Cudos' select had a predicate which was impossible, in the sense that it had no chances to become true.
Dmitry
I'm gonna go have a drink - you should to.
fupsduck
And that means all of you.
fupsduck
I'll buy fup ;)
Kevin Peno
+1  A: 

You can do it using intersection of sets

SELECT id FROM table WHERE type = 1
  INTERSECT
SELECT id FROM table WHERE type = 2
  INTERSECT
SELECT id FROM table WHERE type = 3

I am thinking if there is also simplier query but now I have no idea

Gaim
MySQL doesn't have INTERSECT.
Tordek
oops, my fault. I usually use Oracle and there is this implemented
Gaim
A: 

I like tordek's answer the best, but here is a sloppy example of how to use group_concat in mysql to pull off similar matching.

The advantage of this is that you don't have to change it too much (other than altering the having) if you need to match MORE types later. The downside of course is that you cannot index the pseudo-column inthe select, which may or may not make a difference depending on your application.

You can also create the entire query (minus the having) as a view and then perform a select on it anytime you need. The view will not be writable, but if it fits your needs, yay! Then filter it using WHERE type LIKE...etc ;)

SELECT DISTINCT id, CONCAT( " ", GROUP_CONCAT( type SEPARATOR " " ), " " ) as type
     FROM table
GROUP BY id
HAVING type LIKE "% 1 %" AND type LIKE "% 2 %" AND type LIKE "% 3 %"

Wrap this in another subselect like so to get just the id.

SELECT id
    FROM(
         SELECT DISTINCT id, CONCAT( " ", GROUP_CONCAT( type SEPARATOR " " ), " " ) as type
             FROM table
         GROUP BY id
         HAVING type LIKE "% 1 %" AND type LIKE "% 2 %" AND type LIKE "% 3 %"
  ) t
Kevin Peno
Anger downvotes are the bestest. :D
Kevin Peno
Downvoting because pattern matching predicates wil hardly make use of any index and will definitely be slow, comparing to subselects and joins.
Dmitry
You're right, but with abstraction comes a performance hit. You get the benefit of never having to edit the query for other searches (via a view), but you cannot index the concat values. I've added this information to the answer. I can tell you, however, that I've used this practice in the field and the queries (even on a million records) work very fast (faster than most subselects I tried before I reached this final pattern) provided you don't approach 100's of records on the intersect.
Kevin Peno