Запрос с использованием JOIN вместо INTERSECT - PullRequest
2 голосов
/ 23 июля 2010

У меня есть такая схема:

// table badge_types
id | name
+++|++++++++++
1  | mentor
2  | proctor
3  | doctor

// table badges
id | badge_type_id | user_id     
+++|+++++++++++++++|++++++++
1  | 1             | 5
2  | 1             | 6
3  | 2             | 6
4  | 3             | 6
5  | 2             | 19
6  | 3             | 20

Что я хочу сделать, это выбрать все badge_types, которые конкретный пользователь еще не получил.В приведенном выше примере вызов запроса для:

user_id = 5 возвращает badge_type_id 2 и 3

user_id = 6 возвращает empty set (пользователь получил их всеуже)

user_id = 19 возвращает badge_type_id 1 и 3

Я могу сделать это с помощью предложения INTERSECT.Но мне интересно, можно ли это сделать простым JOIN?Любая помощь будет оценена.

1 Ответ

13 голосов
/ 23 июля 2010

Использование LEFT JOIN / IS NULL:

   SELECT bt.name
     FROM BADGE_TYPES bt
LEFT JOIN BAGDES b ON b.badge_type_id = bt.id
                  AND b.user_id = ?
    WHERE b.id IS NULL

Использование NOT EXISTS

   SELECT bt.name
     FROM BADGE_TYPES bt
    WHERE NOT EXISTS(SELECT NULL
                       FROM BADGES b 
                      WHERE b.badge_type_id = bt.id
                        AND b.user_id = ?)

Использование NOT IN

   SELECT bt.name
     FROM BADGE_TYPES bt
    WHERE bt.id NOT IN (SELECT b.badge_type_id
                       FROM BADGES b 
                      WHERE b.user_id = ?)

MySQL

Если столбцы не обнуляются, лучшим выбором будет LEFT JOIN / IS NULL . Если они обнуляемы, NOT EXISTS и NOT IN являются лучшим выбором .

SQL Server

Помните, что на SQL Server, NOT IN и NOT EXISTS работают лучше, чем LEFT JOIN / IS NULL, если рассматриваемые столбцы не обнуляются .

Oracle

Для Oracle все три эквивалентны, но LEFT JOIN / IS NULL и NOT EXISTS предпочтительнее, если столбцы не обнуляются .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...