Поиск записей в одной таблице, которым нет соответствия в другой таблице
Вариантов для выборки строк из таблицы, для которых нет соответствия в другой таблице я знаю три.
Если ваша СУБД не умеет выполнять вложенные запросы (например MySQL версий ниже 4.1), то выбор у вас только один:
SELECT *
FROM table1 LEFT JOIN table2 ON table1.id=table2.id
WHERE table2.id IS NULL;
Если же вы используете полноценную СУБД, ну по крайней мере умеющую выполнять подзапросы SELECT
, то кроме вышеназваного варианта, есть еще два. Один построен с использованием конструкции NOT IN
, другой с использованием NOT EXISTS
.
SELECT *
FROM table1
WHERE id NOT IN (SELECT id FROM table2 WHERE id IS NOT NULL);
SELECT *
FROM table1
WHERE NOT EXISTS (SELECT id FROM table2 WHERE id=table1.id);
По скорости исполнения вариант с LEFT JOIN
сильно проигрывает вариантам со вложеными запросами. Вариант с NOT IN
всегда быстрее варианта с NOT EXIST
в случаях, когда число записей в таблице table1 больше числа записей в таблице table2. В противном случае, NOT IN
оказывается быстрее только на таблицах с небольшим числом записей, а на больших объемах уже проигрывает NOT EXIST
. Причем чем больше записей в таблице table2 тем существеннее разница в скорости выполнения. Но только при наличии индекса по полю id!
Но пусть вас не смущает эта хитрая арифметика. На таблицах с числом записей до десятка, а то и сотен тысяч, разница во времени исполнения запросов минимальна. И поэтому смело можете пользоваться любым из предложенных запросов. Какой вам больше нравится, либо, кажется проще и понятнее, тем и пользуйтесь. Главное что результат выборки получается у всех одинаковый!
(#) Евгений:
Хочу добавить замечание к запросу NOT IN:
подзапрос должен иметь вид (SELECT id FROM table2 WHERE id IS NOT NULL), иначе результат будет неверным
(#) Dimka:
Евгений, спасибо!
Исправил.
(#) Сергей:
Мужик, спасибо тебе!
Очень помогла статья))
(#) inverser:
Благодарю, друг!
(#) andrey mailinator:
а еще можно с WITH сделать. Тоже неплохой вариант и даже более читабельный чем со сложенными запросами. Но только для Mysql версии 8 и выше:
WITH tab2 AS ( SELECT id FROM table2 WHERE id=table1.id
)
SELECT * FROM table1 JOIN tab2 ON table1.id=tab.id WHERE NOT EXISTS tab2;