2016-10-24 1 views
0

Мне нужно вернуть различия между двумя таблицами.Как сделать запрос, который будет возвращать различия между двумя таблицами в PostgreSQL

создавать временные таблицы

CREATE TEMP TABLE first(
    zoom smallint NOT NULL, 
    x integer NOT NULL, 
    y integer NOT NULL 
); 

CREATE TEMP TABLE second(
    zoom smallint NOT NULL, 
    x integer NOT NULL, 
    y integer NOT NULL 
); 

ВСТАВИТЬ DATA

INSERT INTO first(zoom,x,y) VALUES(5,2,25); 
INSERT INTO first(zoom,x,y) VALUES(5,4,45); 
INSERT INTO first(zoom,x,y) VALUES(5,7,34); 
INSERT INTO first(zoom,x,y) VALUES(5,45,40); 
INSERT INTO first(zoom,x,y) VALUES(5,72,63); 
INSERT INTO second(zoom,x,y) VALUES(5,2,25); 
INSERT INTO second(zoom,x,y) VALUES(5,4,45); 
INSERT INTO second(zoom,x,y) VALUES(5,7,34); 

Wanted результат:

In table first there are extra rows: 
5,45,40 
5,72,63 

Редактировать

Извините, но я понял, что мои исходные данные в значительной степени сложны, чем образец, который я предоставил. Поэтому в исходных данных таблица сначала состоит из 900 строк, а вторая - из 935 строк. Я предположил, что строки различны в каждой таблице, однако, поскольку я не уверен сейчас, поэтому я хотел бы включить это условие в запрос. Я предположил, что запрос вернет 35 строк в качестве различия, потому что я был очень уверен, что все zoom/x/y будут такими же, кроме этого 35. Однако теперь это может быть так. Поэтому в основном то, что мне нужно знать, это различия между двумя таблицами, независимо от того, какой подход лучше всего решить.

Могу ли я получить что-то вроде этого:

zoom | x | y | first |second 
------+----+--- +-------+------ 
    5 | 45 | 40 | yes | no | 

заказ на первый да, второй нет

zoom | x | y | first |second 
------+----+--- +-------+------ 
    5 | 45 | 40 | yes | no | 
    5 | 45 | 40 | yes | no | 
    5 | 45 | 40 | yes | no | 

тогда первый нет, второй да

zoom | x | y | first |second 
------+----+--- +-------+------ 
    5 | 45 | 40 | no | yes | 
    5 | 45 | 40 | no | yes | 
    5 | 45 | 40 | no | yes | 
+1

Вы заинтересованы только в случае примера (строки, которые находятся в «первой» таблице, но не во втором) или также в другом случае? – Insac

+0

После вашего «редактирования»: возможно, вы должны удалить последнее «первое нет, второе нет»: если обе таблицы не имеют строк, где должен выполняться запрос этих строк? – Insac

+0

@Insac Спасибо, что –

ответ

1

Как вы хотите сравнить все столбцы обе таблицы, вы можете использовать полное внешнее соединение для всех столбцов и проверить, является ли один из них:

select case 
      when f.zoom is null then 'missing in first' 
      when s.zoom is null then 'missing in second' 
     end as status, 
     zoom, x, y 
from "first" f 
    full outer join second s using (zoom, x, y) 
where f.zoom is null or s.zoom is null; 

инфа на основе using() будет возвращать те столбцы, которые не NULL (и только те столбцы - удаление дубликатов столбцов из результата)

При использовании данных выборки из вопроса, то результат будет :

status   | zoom | x | y 
------------------+------+----+--- 
missing in second | 5 | 45 | 40 
missing in second | 5 | 72 | 63 

Если добавлена ​​строка во второй таблице, которая не существует в первой, например,:

INSERT INTO second(zoom,x,y) VALUES(15,7,34); 

тогда результат будет:

status   | zoom | x | y 
------------------+------+----+--- 
missing in second | 5 | 45 | 40 
missing in second | 5 | 72 | 63 
missing in first | 15 | 7 | 34 
+0

Этот запрос вернул мне 859 строк. –

+0

Большое спасибо! Я выбрал этот ответ как правильный, потому что он возвращает результаты orderd по статусу! –

+1

@newbie_girl: это чистое совпадение, поскольку в моем запросе нет «порядка». Если вам нужно быть уверенным ** о заказе, вы должны добавить 'order by' –

1

Вот один метод:

select max(which) as AppearsIn, x, y, zoom 
from ((select 'first' as which, x, y, zoom from first) union all 
     (select 'second', x, y, zoom from second) 
    ) x 
group by x, y, zoom 
having count(*) = 1; 

Это предполагает, что строки различаются в каждой таблице.

+0

Маленькая вещь: 'z zoom' вместо' zoom' – Insac

+0

Пожалуйста, взгляните на мой отредактированный вопрос. Этот запрос возвращает меня: 940 строк. –

+0

Ах! Таким образом, этот запрос вернет: 859 строк. Предыдущий комментарий будет удален, если я получу возможность его удалить. –

2

Вы можете использовать EXCEPT

select zoom,x,y from first 
except 
select zoom,x,y from second 

или я-то здесь отсутствует

Если вы хотите удобства сопоставления записей из двух таблиц, то

select * from 
(
select zoom,x,y from first 
except 
select zoom,x,y from second 
) a 
union all 
select * from 
(
select zoom,x,y from second 
except 
select zoom,x,y from first 
) b 
+0

Я отвечал, как вы вчера, на аналогичный вопрос, но ОП не указал, будут ли строки, которые будут извлекаться, только на «первой» таблице или если она заинтересована также в строках во второй таблице, которые не входят в первую. – Insac

+0

@Insac - * В таблице сначала есть дополнительные строки: *, поэтому я думаю, что OP смотрит только в первую таблицу. Подождите, пока OP не выяснит –

+0

Я отредактировал мой вопрос. Взгляни, пожалуйста. Итак, первый запрос с EXCEPT вернет мне строки, которые сначала находятся в таблице, а теперь в таблице? Возвращаемые строки: 412. –

1

Если вы хотите возможные дубликаты несовпадений, вы должны сосчитать:

SELECT COALESCE(f.zoom,s.zoom) AS zoom 
     , COALESCE(f.x,s.x) AS x 
     , COALESCE(f.y,s.y) AS y 
     , COALESCE(f.fcnt,0) AS fcnt 
     , COALESCE(s.scnt,0) AS scnt 
FROM (SELECT DISTINCT zoom,x,y 
     , COUNT (*) AS fcnt 
     FROM first 
     GROUP BY zoom,x,y 
     ) f 
FULL OUTER JOIN (SELECT DISTINCT zoom,x,y 
     , COUNT (*) AS scnt 
     FROM second 
     GROUP BY zoom,x,y 
     ) s USING (zoom,x,y) 
WHERE f.fcnt IS NULL OR s.scnt IS NULL 
     ;