Michele Mariotti
Michele Mariotti

Reputation: 7459

SQL exclude rows without subquery

I have these tables:

PERSON               COURSE               PERSON_COURSE
+----+----------+    +----+----------+    +------+------+
| ID | Name     |    | ID | Name     |    | P_ID | C_ID |       
+----+----------+    +----+----------+    +------+------+
| P1 | Person 1 |    | C1 | Course 1 |    | P1   | C1   |
| P2 | Person 2 |    | C2 | Course 2 |    | P1   | C2   |
| P3 | Person 3 |    | C3 | Course 3 |    | P3   | C2   |
+----+----------+    +----+----------+    | P3   | C3   |
                                          +------+------+

and I want to select all persons which does not attend course C1.

So I'm using:

select p.id
from person p
where p.id not in (
    select pc.p_id 
    from person_course pc
    where pc.c_id != 'C1')

Now, I'm wondering if it's possible to obtain the same result without using a subquery.

Upvotes: 3

Views: 193

Answers (3)

Gordon Linoff
Gordon Linoff

Reputation: 1269753

I just want to point out that you can do this using a subquery, but it is not the one in the question. Instead:

select p.id
from person p
where p.id not in (select pc.p_id 
                   from person_course pc
                   where pc.c_id = 'C1'
---------------------------------^
                  );

(Although I prefer NOT EXISTS for this logic, I am keeping this as similar to your logic as possible.)

Be careful with double negatives.

Upvotes: 1

Joachim Isaksson
Joachim Isaksson

Reputation: 180917

One option is a left join, trying to match people with the course and including only people where there is no match;

SELECT p.* 
FROM person p
LEFT JOIN person_course pc
  ON p.id = pc.p_id
 AND pc.c_id = 'C1'
WHERE pc.c_id IS NULL;

An SQLfiddle to test with.

Upvotes: 3

Lukasz Szozda
Lukasz Szozda

Reputation: 175686

I want to select all persons which does not attend course C1.

You could use aggregation:

SELECT P.ID, P.NAME
FROM PERSON P
LEFT JOIN PERSON_COURSE PC
  ON P.ID = PC.P_ID
GROUP BY P.ID, P.NAME
HAVING SUM(CASE WHEN PC.C_ID = 'C1' THEN 1 ELSE 0 END) = 0;

LiveDemo

Output:

╔════╦══════════╗
║ ID ║   Name   ║
╠════╬══════════╣
║ P2 ║ Person 2 ║
║ P3 ║ Person 3 ║
╚════╩══════════╝

Upvotes: 1

Related Questions