Mysql: выберите строки из таблицы, которых нет в другой

118

Как выбрать все строки в одной таблице, которые не отображаются в другой?

Таблица 1:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Таблица 2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Tia       | Carrera  | 1975-09-18 |
| Nikki     | Taylor   | 1972-03-04 |
+-----------+----------+------------+

Пример вывода для строк в Table1, которых нет в Table2:

+-----------+----------+------------+
| FirstName | LastName | BirthDate  |
+-----------+----------+------------+
| Yamila    | Diaz     | 1972-03-04 |
+-----------+----------+------------+

Может, должно сработать что-то вроде этого:

SELECT * FROM Table1 WHERE * NOT IN (SELECT * FROM Table2)
Кристофер Рапцевич
источник

Ответы:

96

Если у вас 300 столбцов, как вы упомянули в другом комментарии, и вы хотите сравнить все столбцы (при условии, что все столбцы имеют одно и то же имя), вы можете использовать a NATURAL LEFT JOINдля неявного объединения всех совпадающих имен столбцов между двумя таблицами, чтобы вы не нужно вручную набирать все условия соединения:

SELECT            a.*
FROM              tbl_1 a
NATURAL LEFT JOIN tbl_2 b
WHERE             b.FirstName IS NULL
Зейн Бьен
источник
Обратите внимание, что это работает должным образом, только когда ни один из столбцов не имеет значений NULL. В MySQL NULL! = NULL, поэтому каждая строка, имеющая значение NULL, будет возвращена, даже если есть повторяющаяся строка во второй таблице.
Кайл Кочис
84
Если у вас 300 столбцов, вам следует изменить структуру базы данных.
Iharob Al Asimi 01
эй, у меня тоже работает, спасибо! но будет ли это проблемой, если количество строк> 300, как вы упомянули выше?
thekucays
Я все еще не понимаю, что такое запрос ... что, если я, например, изменю «где b.FirstName имеет значение null» на «где b.LastName равно null»? какая разница? извините, что спросил об этом, я все еще новичок в sql: D
thekucays
184

Вам нужно сделать подвыбор на основе имени столбца, а не *.

Например, если у вас есть idполе, общее для обеих таблиц, вы можете:

SELECT * FROM Table1 WHERE id NOT IN (SELECT id FROM Table2)

Дополнительные примеры см. В синтаксисе подзапроса MySQL .

Stennie
источник
1
Спасибо за разъяснения! но мне действительно не нужно основывать выбор строк на каком-либо поле, потому что меня интересуют любые варианты любого поля в строке ...
Если есть только несколько столбцов для сравнения, вы можете выполнить соединение, как в примере @ Steve. Если вы на самом деле запрашиваете общее сравнение данных в двух таблицах с множеством столбцов, вы, вероятно, захотите поискать инструмент сравнения MySQL .
Стенни 01
2
Обратите внимание, что это всегда будет возвращать пустой набор, если столбец, который вы просматриваете в Table2, содержит нули. Не проблема, если вы делаете это на основе первичного ключа, но актуально для людей, пытающихся использовать этот запрос в других контекстах.
Марк Эмери
4
Но что, если мы говорим о больших данных? А Table2 содержит, например, 100M строк?
Frops
Умный и умный ответ. Спасибо, приятель
Анджана Сильва
44
SELECT *
FROM Table1 AS a
WHERE NOT EXISTS (
  SELECT *
  FROM Table2 AS b 
  WHERE a.FirstName=b.FirstName AND a.LastName=b.Last_Name
)

EXISTS поможет вам...

Рузбех Ирани
источник
2
Хороший ответ, экономичный для больших наборов данных, спасибо.
ekerner 08
Strong. Лучший ответ для больших наборов данных
Ян Чедвик,
35

Стандартное LEFT JOIN может решить проблему и, если поля при объединении проиндексированы,
также должно быть быстрее

SELECT *
FROM Table1 as t1 LEFT JOIN Table2 as t2 
ON t1.FirstName = t2.FirstName AND t1.LastName=t2.LastName
WHERE t2.BirthDate Is Null
Стив
источник
хорошо, я думаю, это должно быть так, кстати, почему WHERE t2.Birthdate Is Nullвместо AND t1.Birthdate = t2.Birthdate?
Потому что, если вы добавите это, тогда будет возвращена каждая строка, вы говорите, что в выводе должны появиться только строки, не во второй таблице
Стив
1
Это отличный ответ, так как он не требует возврата всех строк Table2!
dotancohen
Согласен, отличный ответ. У меня есть таблица «человек-много» между 4 таблицами, размещение AND во внутреннем соединении определенно будет более экономичным.
ДР.
6

Пытаться:

SELECT * FROM table1
    LEFT OUTER JOIN table2
    ON table1.FirstName = table2.FirstName and table1.LastName=table2.LastName
    WHERE table2.BirthDate IS NULL
Сачин Пундир
источник
4

Попробуйте этот простой запрос. Работает отлично.

select * from Table1 where (FirstName,LastName,BirthDate) not in (select * from Table2);
Vijesh
источник
-3

Это сработало для меня в Oracle:

SELECT a.* 
    FROM tbl1 a 
MINUS 
SELECT b.* 
    FROM tbl2 b;
Геннадий Сорочан
источник
Вопрос был о MySQL.
jelder
-6
SELECT a.* FROM 
FROM tbl_1 a
MINUS
SELECT b.* FROM 
FROM tbl_2 b
Ингрид Р. Форсейл
источник