2016-02-28 3 views
2

У меня есть эти таблицы:SQL исключить строки без подзапроса

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 | 
              +------+------+ 

и я хочу, чтобы выбрать всех лиц, которые не посещают курс C1.

Поэтому я использую:

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

Теперь мне интересно, если это возможно, чтобы получить тот же результат без использования подзапроса.

ответ

3

Одним из вариантов является левым присоединиться, пытаясь соответствовать людям с курсом и я ncluding только людей, где нет соответствия;

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.

1

Я хочу выбрать всех лиц, которые не посещают курс C1.

Вы можете использовать агрегирование:

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

Выход:

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

Я просто хочу указать, что вы можете сделать это, используя подзапрос, но это не тот вопрос. Вместо этого:

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

(Хотя я предпочитаю NOT EXISTS для этой логики, я держу это как аналог вашей логике, как это возможно.)

Будьте осторожны с двойным негативов.

Смежные вопросы