163

我在数据库中有两个具有绑定主键的表,我希望在它们之间找到一个不相交的集合。例如,

  • Table1有列 ( ID, Name) 和样本数据:(1 ,John), (2, Peter), (3, Mary)
  • Table2有列 ( ID, Address) 和样本数据:(1, address2), (2, address2)

那么如何创建一个 SQL 查询,以便我可以从中获取 IDtable1不在的行table2。在这种情况下,(3, Mary)应该退货吗?

PS: ID 是这两个表的主键。

4

6 回答 6

257

尝试这个

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)
于 2012-08-21T05:01:18.750 回答
127

利用LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL
于 2012-08-21T05:00:51.207 回答
32

基本上有 3 种方法not existsnot inleft join / is null

IS NULL 左连接

SELECT  l.*
FROM    t_left l
LEFT JOIN
        t_right r
ON      r.value = l.value
WHERE   r.value IS NULL

不在

SELECT  l.*
FROM    t_left l
WHERE   l.value NOT IN
        (
        SELECT  value
        FROM    t_right r
        )

不存在

SELECT  l.*
FROM    t_left l
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    t_right r
        WHERE   r.value = l.value
        )

哪一个更好?这个问题的答案可能最好分解为主要的特定 RDBMS 供应商。一般来说,select ... where ... in (select...)当子查询中的记录数大小未知时,应避免使用。一些供应商可能会限制尺寸。例如,Oracle 的限制为 1,000。最好的办法是尝试所有三个并显示执行计划。

NOT EXISTS具体形成 PostgreSQL ,其执行计划LEFT JOIN / IS NULL是一样的。我个人更喜欢这个NOT EXISTS选项,因为它更好地显示了意图。毕竟语义是您想在 A 中查找其 pk不存在于 B中的记录。

旧但仍然是黄金,虽然特定于 PostgreSQL:https ://explainextended.com/2009/09/16/not-in-vs-not-exists-vs-left-join-is-null-postgresql/

于 2019-04-04T23:47:23.930 回答
11

快速替代

我使用两个表进行了一些测试(在 postgres 9.5 上),每个表都有约 2M 行。下面的这个查询比提出的其他查询至少好 5*:

-- Count
SELECT count(*) FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2;

-- Get full row
SELECT table1.* FROM (
    (SELECT id FROM table1) EXCEPT (SELECT id FROM table2)
) t1_not_in_t2 JOIN table1 ON t1_not_in_t2.id=table1.id;
于 2016-08-23T14:04:20.607 回答
5

请记住上面@John Woo 的评论/链接中提出的观点,这就是我通常会如何处理它:

SELECT t1.ID, t1.Name 
FROM   Table1 t1
WHERE  NOT EXISTS (
    SELECT TOP 1 NULL
    FROM Table2 t2
    WHERE t1.ID = t2.ID
)
于 2016-12-20T13:42:33.953 回答
2
SELECT COUNT(ID) FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For count


SELECT ID FROM tblA a
WHERE a.ID NOT IN (SELECT b.ID FROM tblB b)    --For results
于 2015-12-08T21:17:50.577 回答