SQL查询以查找ID不在另一个表中的记录


123

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

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

那么,如何创建一个SQL查询,所以我可以用ID读取该行从table1不在table2。在这种情况下,(3, Mary)应该退货吗?

附言 该ID是这两个表的主键。

提前致谢。


3
作为未来问题的提示:始终定义您正在使用的数据库系统(以及该数据库的哪个版本)。SQL只是大多数数据库系统使用的结构化查询语言 -并没有太大帮助...通常,数据库具有超出ANSI / ISO SQL标准的扩展和功能,从而使解决问题变得容易-但为此,您需要告诉我们您正在使用什么数据库
marc_s 2012年

5
@marc_s:如果他们正在寻找与语言无关的解决方案,因为他们需要支持多个底层数据库系统,或者数据库实现被抽象化了怎么办?
dwanderson

嗨@mar​​c_s,在这种情况下,我使用的是PostgreSQL。感谢您的提醒。
johnklee

Answers:


213

试试这个

SELECT ID, Name 
FROM   Table1 
WHERE  ID NOT IN (SELECT ID FROM Table2)

8
@PrinceJea实际上取决于。看到这里澄清
吴宇森

当我有20个数据时,它可以工作,但是当我有20000个数据时,它不能工作,我现在感到困惑。
弗兰克(Frank)

1
不知道为什么,但是它不起作用。我在表中有大约10000行。以我为例,@ JohnWoo的解决方案很好用。
Munam Yousuf

4
如果“ Not In”中的值太多,将无法使用,因为此方法的值数量有限cf:dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm
G.Busato

2
我必须这样做:从表1中选择我不在的位置(从表2 选择i ,其中i不为null)和i 不为null
jaksco

93

LEFT JOIN

SELECT  a.*
FROM    table1 a
            LEFT JOIN table2 b
                on a.ID = b.ID
WHERE   b.id IS NULL

我认为这对于大型数据库而言是更快的方法
Alex Jolig

12

基本上有三种途径到: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。最好的办法是尝试所有这三个步骤并显示执行计划。

具体而言,PostgreSQL的执行计划NOT EXISTSLEFT 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/


10

快速替代

我使用两个约200万行的表运行了一些测试(在postgres 9.5上)。与下面提出的其他查询相比,下面的查询至少要好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;

1
这并不比@Jhon Woo的解决方案快。我使用的是Postgres 9.6,Jhon的解决方案运行时间约为60毫秒。虽然我在120秒后就解决了这个问题,但没有结果。
froy001

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
)

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