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

表1中不在表2中的行的示例输出:

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

也许这样的事情应该工作:

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

Answers:


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

嘿,这对我也有用,谢谢!但是如果行数大于300(如上所述),那会是一个问题吗?
thekucays's

我对查询btw仍然感到困惑。例如,如果我将“ where b.FirstName is null”更改为“ where b.LastName is null”,那该怎么办?有什么不同?我很抱歉问这个问题,我对sql还是
陌生的

184

您需要基于列名进行子选择,而不是 *

例如,如果您有id两个表共有的字段,则可以执行以下操作:

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

有关更多示例,请参考MySQL子查询语法


1
感谢您的澄清!但是我真的不需要将行的选择基于任何字段,因为我对行中任何字段的任何变化都感兴趣...

如果只有几列要比较,则可以按照@Steve的示例进行联接。如果您实际上是在对两列有很多列的表中的数据进行一般比较,则可能需要寻找MySQL diff工具
Stennie 2012年

2
请注意,如果您在Table2中查看的列包含空值,则它将始终返回一个空集。如果您基于主键进行操作,这不是问题,但与尝试在其他上下文中使用此查询的人们有关。
Mark Amery 2014年

4
但是,如果我们谈论的是大数据呢?例如,Table2包含1亿行?
收成2016年

聪明而聪明的答案。感谢队友
Anjana Silva

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 2014年

强大。大型数据集的最佳答案
伊恩·查德威克

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

因为如果添加了该行,那么将返回每一行,因此您说输出中应该只显示第二行中没有的行
Steve

1
这是一个了不起的答案,因为它不需要返回Table2!的所有行。
dotancohen 2013年

我同意,很好的答案。我在4个表之间有一个多人桌,将AND放在内部联接中肯定会更经济。
DR。

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);


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.