我在数据库中有两个带有绑定主键的表,我希望在它们之间找到一个不相交的集合。例如,
Table1
包含列(ID, Name
)和示例数据:(1 ,John), (2, Peter), (3, Mary)
Table2
包含列(ID, Address
)和示例数据:(1, address2), (2, address2)
那么我该如何创建一个SQL查询,以便我可以获取table1
中不在table2
中的ID的行。在这种情况下,应该返回(3, Mary)
?
Ps。 ID是这两个表的主键。
提前致谢。
答案 0 :(得分:163)
试试这个
SELECT ID, Name
FROM Table1
WHERE ID NOT IN (SELECT ID FROM Table2)
答案 1 :(得分:73)
使用LEFT JOIN
SELECT a.*
FROM table1 a
LEFT JOIN table2 b
on a.ID = b.ID
WHERE b.id IS NULL
答案 2 :(得分:8)
我运行了一些测试(在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;
答案 3 :(得分: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
)
答案 4 :(得分:3)
基本上有3种方法可以使用:not exists
,not in
和left 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 EXISTS
和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/
答案 5 :(得分:1)
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