views:

445

answers:

7

I have table structure like this:

ID   cond
1    5
1    2
1    6
8    2
9    1
9    5

When I want to select rows that contain one or more conditions i use OR (...WHEN cond=2 OR cond=6 GROUP BY ID...)

But how to select rows that contain more than one condition simultaneously grouped by ID? E.g. when i want to find rows that contain cond 2 and 6, it returns only ID 1

Thanks

+3  A: 

You can use a join for this:

SELECT  ID
FROM    tbl t1
        INNER JOIN
                tbl t2
                ON t1.ID = t2.ID
WHERE   t1.cond = 2
AND     t2.cond = 6

Or this, if ID/cond pairs are unique:

SELECT  ID
FROM    tbl
WHERE   cond IN (2, 6)
GROUP BY ID
HAVING COUNT(cond) = 2
David M
@David M: I like this, but only for this case. For any extra values that need to be included, it requires another join, which can get expensive if you have to verify many values exist.
casperOne
True. Trying something else...
David M
@David M: See my solution for the general case. It's more SQL Server specific, but I'm sure there is a MySQL equivalent. =)
casperOne
With this type of JOIN, it is sometimes more obvious what is going on if the constraint is added to the JOIN clause; eg "INNER JOIN tbl t2 ON t1.ID = t2.ID AND t2.cond = 6". Even further "FROM tbl JOIN tbl t1 ON t1.ID = tbl.ID and t1.cond = 2" so all constraints display nicely.
Chris Shaffer
Nice second option (HAVING COUNT ...). Wish I could upmod again :)
Chris Shaffer
@David, you can always use COUNT(DISTINCT ...)
vladr
A: 
SELECT DISTINCT(ID) WHERE (cond = 2) OR (cond = 6)
Andrew Rollings
The OP wants where both cond values appear for an Id, from what they've said
Rowland Shaw
Hmm.. I dunno. The question needs editing to clarify.
Andrew Rollings
A: 

Here's another syntax that is a little more transparent (although not as performant) about what it is doing.

SELECT DISTINCT ID 
FROM MyTable T
WHERE 
  EXISTS(SELECT ID FROM MyTable T1 WHERE Cond=2 AND T1.ID=T.ID) AND
  EXISTS(SELECT ID From MyTable T2 WHERE Cond=6 AND T2.ID=T.ID)
JohnFx
+1  A: 

You could use subqueries and a group to do this. Assuming you know the number of values you need to find, you can do this:

select
    t.ID
from
    (
        select distinct
            ID, cond
        from
            tbl
        where
            tbl.cond in (2, 6)
    ) as t
group by
    t.ID
having
    count(t.cond) = 2

For the general case, you would simply have to update the list of conditions that must exist (i.e. "(2, 6)") to include the new values, and then update the having clause (i.e. "having count(t.cond) = 2") to equal the total number of values.

casperOne
A: 

This might be a little more flexable if there are no dups per id.

SELECT id
FROM tbl 
GROUP BY id
HAVING SUM(CASE cond 
    WHEN 2 THEN 1
    WHEN 6 THEN 1
    ELSE 0 END) > 1
+2  A: 

There are multiple ways of doing this.

Using COUNT (fastest):

SELECT id FROM tbl WHERE tbl.cond IN ( 2, 6 ) HAVING COUNT(DISTINCT cond) = 2 GROUP BY id

Using EXISTS (using nested loops, slower on very large tables, but less cryptical and more xtensible than the COUNT variant):

SELECT DISTINCT id FROM tbl AS tbl1 WHERE EXISTS (SELECT * FROM tbl AS tbl2 WHERE tbl1.id = tbl2.id AND tbl2.cond = 2) AND EXISTS (SELECT * FROM tbl AS tbl2 WHERE tbl1.id = tbl2.id AND tbl2.cond = 6)

Using GROUP_CONCAT (a MySql specific variation on the COUNT theme, but if you ever want exact matches, e.g. cond=2 and cond=6 an no other cond, then the below, altered to read SELECT id, GROUP_CONCAT(DISTINCT cond ORDER BY cond) AS conds ... WHERE conds='2,6' will perform best)

SELECT id, ','||GROUP_CONCAT(DISTINCT cond)||',' AS conds FROM tbl WHERE INSTR(conds, ',2,') > 0 AND INSTR(conds, ',6,') > 0 GROUP BY id

Cheers, V.

vladr
Thanks....Pls, is it possible to use first variant when it's one more condition (column) (e.g. when it's (cond=2 and cond2=1) and (cond=6 and cond2=2))?
Bajlo
I'd say, yes: SELECT id FROM tbl WHERE tbl.cond IN ( 2, 6 ) AND tbl.cond2 IN ( 1, 2 ) HAVING COUNT(DISTINCT cond) = 2 AND COUNT(DISTINCT cond2) = 2 GROUP BY id
vladr
A: 

Have you thought about using the UNION clause?

SELECT ID FROM MyTable WHERE cond = 2 UNION SELECT ID FROM MyTable WHERE cond = 6

It would also help if you could specify the exact output you are looking for. But from what I understood, UNION would be the way to go.

Ralph Wiggum