Here is a table with id and permission as composite primary key, which means one can have some permissions.
id permission
1 'A'
1 'B'
2 'A'
3 'B'
Now I want to select all ids that fit some conditions. For example:
idWITH permission 'A' AND 'B'.idWITH permission 'A' AND WITHOUT permission 'B'.
I've come up with a kind of sql which uses exists clause.
For 1:
SELECT DISTINCT t0.id FROM t t0
WHERE
EXISTS (SELECT 1 FROM t t1 WHERE t1.id = t0.id AND t1.permission = 'A')
AND EXISTS (SELECT 1 FROM t t1 WHERE t1.id = t0.id AND t1.permission = 'B');
For 2:
SELECT DISTINCT t0.id FROM t t0
WHERE
EXISTS (SELECT 1 FROM t t1 WHERE t1.id = t0.id AND t1.permission = 'A')
AND NOT EXISTS (SELECT 1 FROM t t1 WHERE t1.id = t0.id AND t1.permission = 'B');
It works, but for large tables, it is slow because it traverses the table multiple times for each record. So I wonder if there is a faster and clearer way to achieve my goal.
You can use
COUNT(DISTINCT)for case 1. Here is the sample:And you can use
NOT INfor case 2. Here is the sample:It should be faster than your initial query that querying exists and/or non exists twice. Here is the fiddle link.