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

Posted

技术标签:

【中文标题】SQL查询以查找ID不在另一个表中的记录【英文标题】:SQL query to find record with ID not in another table 【发布时间】:2012-08-16 10:20:36 【问题描述】:

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

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

那么如何创建 SQL 查询,以便我可以从 table1 中获取 ID 不在 table2 中的行。这种情况下应该返回(3, Mary)

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

【问题讨论】:

作为未来问题的提示:始终定义您正在使用的数据库系统(以及该数据库的哪个版本)。 SQL 只是大多数数据库系统使用的 结构化查询语言 - 它并没有太大帮助......通常,数据库具有超出 ANSI/ISO 的扩展和功能使解决问题变得容易的 SQL 标准 - 但为此,您需要告诉我们您使用的是什么数据库 @marc_s:如果他们正在寻找与语言无关的解决方案,因为他们需要支持多个底层数据库系统,或者数据库实现被抽象掉了怎么办? 嗨@mar​​c_s,在这种情况下我使用的是PostgreSQL。谢谢提醒。 【参考方案1】:

使用LEFT JOIN

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

【讨论】:

我认为对于非常大的数据库来说这是更快的方法【参考方案2】:

试试这个

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

【讨论】:

@PrinceJea 实际上取决于。 See here for clarification 当我有 20 个数据时,它可以工作,但是当我有 20000 个数据时,它不起作用,我现在很困惑。 不知道为什么,但它不起作用。我在表中有大约 10000 行。就我而言,@JohnWoo 的解决方案效果很好。 “Not In”中的值太多是行不通的,因为此方法的值数量有限,请参见:dba-oracle.com/t_maximum_number_of_sql_in_list_values.htm 我必须这样做:从表 1 中选择 i,其中我不在(从表 2 中选择 i 其中 i 不为空)并且 i 不为空【参考方案3】:
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

【讨论】:

【参考方案4】:

快速替代

我使用两个表进行了一些测试(在 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;

【讨论】:

这并不比@Jhon Woo 的解决方案快。我使用的是 Postgres 9.6,Jhon 的解决方案运行时间约为 60 毫秒。虽然我在 120 秒后解决了这个问题,但没有结果。【参考方案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
)

【讨论】:

【参考方案6】:

基本上有 3 种方法:not existsnot inleft join / 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 有一个limit of 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/

【讨论】:

sqlshack.com/… 我将所有这 3 个都绑定在我的存储过程中。第一个建议(LEFT JOIN with IS NULL)是迄今为止最快的。

以上是关于SQL查询以查找ID不在另一个表中的记录的主要内容,如果未能解决你的问题,请参考以下文章

SQL中,如何查询存在一个表而不在另一个表中的数据记录

SQL中,如何查询存在一个表的字段而不在另一个表的字段中的数据记录?

SQL查询 —— 存在一个表而不在另一个表中的数据

sql查询 如何获取查找某ID的一条记录在表中是第几条记录

如何使用 DB2 sql 检查不在两个表中的记录以获取另一个第三个表中的日期?

用于查找一个表中但不在另一个表中的行的 MySQL 查询