Select rows that contain more than one condition simultaneously
-
22-08-2019 - |
Question
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
Solution
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
OTHER TIPS
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
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.
SELECT DISTINCT(ID) WHERE (cond = 2) OR (cond = 6)
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)
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
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.