如何从一个表中选择另一个表中不存在的所有记录?

时间:2010-04-21 20:18:25

标签: sql sql-server tsql

  

table1(id,name)
  table2(id,name)

查询:

SELECT name   
FROM table2  
-- that are not in table1 already

14 个答案:

答案 0 :(得分:699)

SELECT t1.name
FROM table1 t1
LEFT JOIN table2 t2 ON t2.name = t1.name
WHERE t2.name IS NULL

:这里发生了什么?

A :从概念上讲,我们选择table1中的所有行,并且对于每一行,我们尝试在table2中找到name的相同值的行}列。如果没有这样的行,我们只将结果的table2部分留空。然后我们通过仅选择匹配行不存在的结果中的那些行来约束我们的选择。最后,我们忽略了结果中的所有字段,但name列(我们确定存在的列,来自table1)除外。

虽然在所有情况下它可能不是最高性能的方法,但它应该在基本上每个试图实现ANSI 92 SQL的数据库引擎中起作用

答案 1 :(得分:201)

你可以做

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

SELECT name 
FROM table2 
WHERE NOT EXISTS 
    (SELECT * 
     FROM table1 
     WHERE table1.name = table2.name)

有关完成此操作的3种技术,请参阅this question

答案 2 :(得分:64)

我没有足够的代表来推荐第二个答案。但我不同意对最佳答案的评论。第二个答案:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT name 
     FROM table1)

FAR在实践中是否更有效率。我不知道为什么,但是我在800k +记录中运行它,差异很大,因为上面给出的第二个答案给出了优势。只需我0.02美元

答案 3 :(得分:35)

这是纯粹的集理论,您可以使用minus操作来实现。

select id, name from table1
minus
select id, name from table2

答案 4 :(得分:14)

留意陷阱。如果Name中的字段Table1包含Null,则表示您感到意外。 更好的是:

SELECT name
FROM table2
WHERE name NOT IN
    (SELECT ISNULL(name ,'')
     FROM table1)

答案 5 :(得分:13)

这对我来说最有效。

SELECT *
FROM @T1
EXCEPT
SELECT a.*
FROM @T1 a
JOIN @T2 b ON a.ID = b.ID

这比我试过的任何其他方法快两倍。

答案 6 :(得分:13)

SELECT <column_list>
FROM TABLEA a
LEFTJOIN TABLEB b 
ON a.Key = b.Key 
WHERE b.Key IS NULL;

enter image description here

https://www.cloudways.com/blog/how-to-join-two-tables-mysql/

答案 7 :(得分:8)

您可以在mssql中使用EXCEPT或在oracle中使用MINUS,它们根据以下内容相同:

http://blog.sqlauthority.com/2008/08/07/sql-server-except-clause-in-sql-server-is-similar-to-minus-clause-in-oracle/

答案 8 :(得分:7)

这对我来说很明显

SELECT * 
FROM [dbo].[table1] t1
LEFT JOIN [dbo].[table2] t2 ON t1.[t1_ID] = t2.[t2_ID]
WHERE t2.[t2_ID] IS NULL

答案 9 :(得分:0)

查看查询:

SELECT * FROM Table1 WHERE
id NOT IN (SELECT 
        e.id
    FROM
        Table1 e
            INNER JOIN
        Table2 s ON e.id = s.id);

从概念上讲,将是:在子查询中获取匹配的记录,然后在主查询中获取不在子查询中的记录。

答案 10 :(得分:0)

首先定义表的别名,如 t1t2。 之后获取第二张表的记录。 之后使用 where 条件匹配该记录:

SELECT name FROM table2 as t2
WHERE NOT EXISTS (SELECT * FROM table1 as t1 WHERE t1.name = t2.name)

答案 11 :(得分:0)

我尝试了上述所有解决方案,但在我的情况下不起作用。以下查询对我有用。

SELECT name FROM table_1 WHERE name NOT IN (SELECT a.name FROM table_1 AS a 
LEFT JOIN table_2 as b ON a.name = b.name WHERE ANY FURTHER CONDITION );

答案 12 :(得分:0)

上述所有查询在大表上都非常慢。需要改变战略。这是我用于我的数据库的代码,您可以音译更改字段和表名。这是策略:您创建两个隐式临时表并将它们合并。第一个临时表来自第一个原始表的所有行的选择,您要控制的字段不存在于第二个原始表中。第二个隐式临时表包含与您要控制的列/字段的相同值匹配的两个原始表的所有行。联合的结果是一个表,该表具有多个具有相同控制字段值的行,以防在两个原始表中该值匹配(一个来自第一个选择,第二个来自第二个选择)在第一个原始表的值与第二个原始表的任何值不匹配的情况下,只有一行具有控制列值。你分组和计数。当计数为 1 时,不匹配,最后,您只选择计数等于 1 的行。看起来不优雅,但它比上述所有解决方案快几个数量级。 重要说明:启用要检查的列上的 INDEX。

SELECT name, source, id
FROM 
(
    SELECT name, "active_ingredients" as source, active_ingredients.id as id 
        FROM active_ingredients

    UNION ALL
        
    SELECT active_ingredients.name as name, "UNII_database" as source, temp_active_ingredients_aliases.id as id 
    FROM active_ingredients
    INNER JOIN temp_active_ingredients_aliases ON temp_active_ingredients_aliases.alias_name = active_ingredients.name

) tbl
GROUP BY name
HAVING count(*) = 1
ORDER BY name

答案 13 :(得分:-1)

我将以正确的答案重新发布(因为我还没有足够的能力发表评论)。...以防其他人认为需要更好的解释。

SELECT temp_table_1.name
FROM original_table_1 temp_table_1
LEFT JOIN original_table_2 temp_table_2 ON temp_table_2.name = temp_table_1.name
WHERE temp_table_2.name IS NULL

我已经看到FROM中的语法需要在mySQL中的表名之间加逗号,但是在sqlLite中,它似乎更喜欢空格。

最重要的是,当您使用错误的变量名时,它会留下问题。我的变量应该更有意义。有人应该解释为什么我们需要逗号或不需要逗号。