Найти несопоставленные строки между двумя таблицами - PullRequest
0 голосов
/ 28 сентября 2018

При такой настройке:

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 голосов
/ 29 сентября 2018

Дьявол в деталях с этой, казалось бы, простой задачей.

Короткий и один из самых быстрых:

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) в конце - дешевле на несколько dupes:

SELECT DISTINCT col1, col2
FROM ...

Если у вас есть много dupes с обеих сторон, дешевле сложить до объединения:

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 ON или GROUP BY рассматривают их как равные (поэтому дупс со значениями NULL складываются в подзапросах выше).Но условия JOIN или WHERE должны быть равны 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;

Похожие:

0 голосов
/ 28 сентября 2018

Кажется, идеально подходит для операций над множествами:

  ( --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
  )
0 голосов
/ 28 сентября 2018

Один метод - 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.Опасность дубликатов между таблицами отсутствует.

0 голосов
/ 28 сентября 2018

Вы можете попробовать установить операции.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 ALL и UNION ALL).Обычно они работают быстрее, поскольку СУБД не нужно искать и устранять дубликаты.

0 голосов
/ 28 сентября 2018

Вы можете попробовать использовать 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
)
...