如何通过JOIN从另一个表中查找不存在的数据?

时间:2011-09-21 04:23:54

标签: mysql sql join anti-join

我有两个表TABLE1,它们看起来像:

id      name     address
1       mm     123
2       nn     143

和TABLE2 w / c看起来像:

name     age
mm      6
oo      9

我希望通过将TABLE1TABLE2进行比较来获取不存在的名称。

所以基本上,我必须得到第二行,w / c有一个NN名称,TABLE2中不存在,输出应该如下所示:

id      name     address
2      nn      143

我试过这个,但它不起作用:

SELECt  w.* FROM TABLE1 W INNER JOIN TABLE2 V
  ON W.NAME <> V.NAME

它仍在获取现有记录。

2 个答案:

答案 0 :(得分:6)

INNER JOIN在这里没有帮助。

解决此问题的一种方法是使用LEFT JOIN

SELECT w.* 
FROM TABLE1 W 
LEFT JOIN TABLE2 V ON W.name = V.name
WHERE ISNULL(V.name);

答案 1 :(得分:2)

您需要的关系运算符是半差异a.k.a. antijoin

大多数SQL产品缺少明确的半差异运算符或关键字。标准SQL-92没有一个(它有一个MATCH (subquery)半连接谓词但是,虽然很想不这么认为,NOT MATCH (subquery)的语义与半差异的语义不同; FWIW是真正的关系语言Tutorial D成功使用NOT MATCHING半差异。)

半差异当然可以使用其他SQL谓词编写。最常见的是:外部联接,WHERE子句中的空值测试,紧跟着EXISTSIN (subquery)。使用EXCEPT(相当于Oracle中的MINUS)是另一种可能的方法,如果您的SQL产品支持它,并且再次取决于数据(特别是,当两个表的标题相同时)。

就个人而言,我更喜欢在SQL中使用EXISTS进行半差异连接,因为连接子句在编写的代码中更接近,并且不会导致在连接表上进行投影,例如

SELECT *
  FROM TABLE1 W
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM TABLE2 V
                    WHERE W.NAME = V.NAME
                  );

NOT IN (subquery)一样(外连接方法相同),如果子查询中的WHERE子句涉及空值(提示:if WHERE子句,则需要格外小心。子查询由于存在空值而评估UNKNOWN,然后它将被EXISTS强制为FALSE,这可能会产生意外结果。)


更新(3年后):我已经转向更喜欢NOT IN (subquery),因为它更具可读性,如果你担心带有空值的意外结果(你应该这样),那么完全停止使用它们,我多年前做了很多。

更具可读性的一种方法是不需要范围变量WV,例如

SELECT * FROM TABLE1 WHERE name NOT IN ( SELECT name FROM TABLE2 );