2011-04-21 237 views
25

我需要构建一个查询,根据make-model-serial number组合,向我显示表1中的记录,但不在表2中的记录。SQL Server - NOT IN

我知道事实上有4条记录不同,但我的查询总是空白。

SELECT * 
FROM Table1 WHERE MAKE+MODEL+[Serial Number] NOT IN 
(SELECT make+model+[serial number] FROM Table2) 

表1有5条记录。

当我将查询更改为IN时,我得到1条记录。我在做什么错了NOT

+3

你的表中是否有空值? – tobias86 2011-04-21 19:10:06

+0

也许发布您的数据将有所帮助。语法看起来不错。 (虽然psuedo-key有点不好意思) – Randy 2011-04-21 19:11:29

回答

35

这是因为the way NOT IN works

为了避免这些麻烦(和在许多情况下更快的查询),我总是喜欢NOT EXISTS:

SELECT * 
FROM Table1 t1 
WHERE NOT EXISTS (
    SELECT * 
    FROM Table2 t2 
    WHERE t1.MAKE = t2.MAKE 
    AND t1.MODEL = t2.MODEL 
    AND t1.[Serial Number] = t2.[serial number]); 
+0

多数民众赞成它!谢谢! – 2011-04-21 19:14:32

+0

查看我的编辑(在阅读Joe的良好答案后,我改进了我的答案) – 2011-04-21 19:17:19

0

使用LEFT JOIN检查右侧的空值。

SELECT a.Id 
FROM TableA a 
LEFT JOIN TableB on a.Id = b.Id 
WHERE b.Id IS NULL 

上面将匹配基于每个Id列表A表B和,然后给你其中B侧是空的行。

+0

这通常起作用,但IMO并不是一个很好的通用解决方案,因为如果TableB中存在连接谓词的多行,并且如果b .Id恰好是一个空列,你可以得到一个误报。在很多情况下,这是一个有效的解决方案,但是(取决于数据) – 2011-04-21 19:15:10

+0

@DaveMarkle,是的,非常好的警告,谢谢。 – 2011-04-21 19:16:07

6

你可能比单独比较字段更好,而不是连接字符串。

SELECT t1.* 
    FROM Table1 t1 
     LEFT JOIN Table2 t2 
      ON t1.MAKE = t2.MAKE 
       AND t1.MODEL = t2.MODEL 
       AND t1.[serial number] = t2.[serial number] 
    WHERE t2.MAKE IS NULL 
+0

更好 - 在更快? :) – 2011-04-21 19:13:38

+0

我喜欢这个想法 – tobias86 2011-04-21 19:13:53

+0

@xrum:对于列上的索引,我当然会这么认为。 – 2011-04-21 19:15:19

0

一个问题可能是,如果任一品牌,型号,或[序号]为空,值永远不会返回。因为带空值的字符串连接总是会导致null,而不是()中的null将始终不返回任何内容。造成这种情况的补救方法是使用运营商如ISNULL(做,“”)+ ISNULL(型号,“”)等

1
SELECT [T1].* 
FROM [Table1] AS [T1] 
WHERE NOT EXISTS (SELECT 
    1 AS [C1] 
    FROM [Table2] AS [T2] 
    WHERE ([T2].[MAKE] = [T1].[MAKE]) AND 
     ([T2].[MODEL] = [T1].[MODEL]) AND 
     ([T2].[Serial Number] = [T1].[Serial Number]) 
); 
1
SELECT * FROM Table1 
WHERE MAKE+MODEL+[Serial Number] not in 
    (select make+model+[serial number] from Table2 
    WHERE make+model+[serial number] IS NOT NULL) 

为我工作,其中make+model+[serial number]是一个字段名称