查找两个表之间不匹配的行

时间:2018-09-28 20:47:36

标签: sql postgresql duplicates gaps-and-islands

进行以下设置:

CREATE TABLE table1 (column1 text, column2 text);
CREATE TABLE table2 (column1 text, column2 text);

INSERT INTO table1 VALUES
   ('A', 'A')
 , ('B', 'N')
 , ('C', 'C')
 , ('B', 'A');

INSERT INTO table2 VALUES
   ('A', 'A')
 , ('B', 'N')
 , ('C', 'X')
 , ('B', 'Y');

如何在这两个表之间找到(column1, column2) 缺失组合 ?其他表中不匹配的行。

给定示例的预期结果将是:

  C | C
  B | A
  C | X
  B | Y

可能有重复的条目,因此我们想省略这些条目。

5 个答案:

答案 0 :(得分:1)

您可以尝试对子查询使用not exists,然后使用UNION ALL

select Column1,Column2   from table1 t1 
where NOT exists 
(
    select 1 
    FROM table2 t2
    where t1.Column1 = t2.Column1 or t1.Column2 = t2.Column2
)
UNION ALL
select Column1,Column2  from table2 t1 
where NOT exists 
(
    select 1 
    FROM table1 t2
    where t1.Column1 = t2.Column1 or t1.Column2 = t2.Column2
)

答案 1 :(得分:1)

一种方法是union all

select t1.col1, t1.col2
from t1
where (t1.col1, t1.col2) not in (select t2.col1, t2.col2 from t2)
union all
select t2.col1, t2.col2
from t2
where (t2.col1, t2.col2) not in (select t1.col1, t1.col2 from t1);

如果表中的中有重复项,则可以使用select distinct将其删除。在表之间 没有重复的危险。

答案 2 :(得分:1)

您可以尝试设置操作。 EXCEPT查找表中的行,而不查找另一行,UNION将部分结果放入一个。

(SELECT column1,
        column2
        FROM table1
 EXCEPT
 SELECT column1,
        column2
        FROM table2)
UNION
(SELECT column1,
        column2
        FROM table2
 EXCEPT
 SELECT column1,
        column2
        FROM table1);

如果不需要重复消除,可以尝试使用ALL变体(EXCEPT ALLUNION ALL)。它们通常更快,因为DBMS不必查找并消除重复项。

答案 3 :(得分:1)

对于设置操作来说似乎是完美的任务:

  ( --all rows from table 1 missing in table 2
    select *
    from table1
    except 
    select *
    from table2
  )
  union all -- both select return distinct rows
  ( -- all rows in table 2 missing in table 1
    select *
    from table2
    except 
    select *
    from table1
  )

答案 4 :(得分:1)

通过这个看似简单的任务,魔鬼在细节中

简短而最快的:

SELECT col1, col2
FROM        (SELECT col1, col2, TRUE AS x1 FROM t1) t1
FULL   JOIN (SELECT col1, col2, TRUE AS x2 FROM t2) t2 USING (col1, col2)
WHERE  (x1 AND x2) IS NULL;

FULL [OUTER] JOIN包括两侧的所有行,但对于缺少的行的列填充NULL值。 WHERE条件(x1 AND x2) IS NULL标识这些不匹配的行。等效:WHERE x1 IS NULL OR x2 IS NULL

要消除重复对,请在末尾添加DISTINCT(或GROUP BY)-比 便宜骗子:

SELECT DISTINCT col1, col2
FROM ...

如果两边都有 许多 个重复对象,则在连接前折叠 会更便宜:

SELECT col1, col2
FROM        (SELECT DISTINCT col1, col2, TRUE AS x1 FROM t1) t1
FULL   JOIN (SELECT DISTINCT col1, col2, TRUE AS x2 FROM t2) t2 USING (col1, col2)
WHERE  (x1 AND x2) IS NULL;

如果可以存在 NULL值,则更为复杂。 DISTINCT / DISTINCT ONGROUP BY将它们视为相等(因此,具有NULL值的重复项将在上面的子查询中折叠)。但是JOINWHERE条件必须评估为TRUE才能通过行。在这种情况下, 被认为是NULL值相等,FULL [OUTER] JOIN从未找到包含NULL的对的匹配项。这可能是理想的,也可能不是理想的。您只需要了解差异并定义您的要求即可。

考虑在SQL Fiddle

中添加的演示

如果没有NULL值,没有重复项,但是在每个表中定义了NOT NULL的附加列(如主键),让我们为每个id命名,然后可以很简单

SELECT col1, col2
FROM   t1
FULL   JOIN t2 USING (col1, col2)
WHERE  t1.id IS NULL OR t2.id IS NULL;

相关: