Допустим, у меня есть две таблицы (из загруженных файлов CSV), и я хочу выполнить разницу на основе идентификатора + территории в новом файле, которого не было в старом файле. Самый простой способ сделать это - это что-то вроде:
SELECT id, territory FROM this_week EXCEPT SELECT id, territory FROM last_week
Однако я пытаюсь получить ВСЕ поля (в обеих таблицах - по одной строке на ключ), которые генерируются этой разницей. Как это можно сделать?
Подойдет либо postgres, либо bigquery. У обоих есть набор EXCEPT
op.
Пример с данными из ответа Эрвина:
WITH this_week (id,territory,name,other) AS (VALUES(1,'us','titanic','uhd'),(22,'us','spider','hd'),(3,'fr','new','hd')),
last_week (id,territory,name,other) AS (VALUES(1,'us','titanic','uhd'),(2,'us','spider','hd'))
SELECT * -- all columns of "this_week"
FROM this_week t
WHERE NOT EXISTS (
SELECT * FROM last_week l
WHERE t.id = l.id
AND t.territory = l.territory
);
🤔 А знаете ли вы, что...
SQL позволяет объединять данные из разных таблиц с помощью операторов JOIN.
Используйте НЕ СУЩЕСТВУЕТ:
SELECT * -- all columns of "this_week"
FROM this_week t
WHERE NOT EXISTS (
SELECT FROM last_week l
WHERE t.id = l.id
AND t.territory = l.territory
);
А индекс last_week (id, territory)
обычно помогает производительности (очень сильно).
Здесь показаны все столбцы this_week
.
.
Я не вижу смысла добавлять столбцы last_week
, которые были бы пустыми (null
) по определению запроса, если бы вы присоединились слева.
Основы:
Обратите внимание на тонкую разницу:
EXCEPT
(при использовании без ALL
) складывает дубликаты. Этот запрос не делает. Вы можете хотеть того или другого. Обычно вы этого хотите.
Сравнение двух одинаково структурированных таблиц (с одинаковыми именами столбцов в одном и том же порядковом положении) с первичным ключом (уникальным и не допускающим значения NULL) pk:
SELECT t1.*
, t2.*
FROM Table1 t1
FULL JOIN Table2 t2
ON t1.pk = t2.pk
WHERE NOT EXISTS(
SELECT t1.*
INTERSECT
SELECT t2.*
)
Это даст вам все различия между двумя таблицами. Если в обеих таблицах есть совпадающий pk, вы увидите записи, где остальные столбцы где-то отличаются. Если строка находится в t1, а не в t2 (по pk), она появится, если строка находится в t2, а не в t1 (по pk), она появится.
Если таблицы не имеют идентичной структуры, вам нужно будет расширить * в подзапросе и явно перечислить столбцы, которые вы хотите сравнить.
Пример
--Create two identically strctured tables
CREATE TABLE Table1(PK BIGINT NOT NULL
, Col1 BIGINT
, Col2 BIGINT
)
;
CREATE TABLE Table2(PK BIGINT NOT NULL
, Col1 BIGINT
, Col2 BIGINT
)
;
--insert some data into them
INSERT INTO Table1(PK
, Col1
, Col2
)
VALUES
(1, 100, 1000) --Pk In both Table1 and Table2, and contents match
,(2, 101, 1001) --Pk In both Table1 and Table2, and contents do not match
,(3, 102, 1002) --Pk only in Table1
;
INSERT INTO Table2(PK
, Col1
, Col2
)
VALUES
(1, 100, 1000) --Pk In both Table1 and Table2, and contents match
,(2, 0, 0) --Pk In both Table1 and Table2, and contents do not match
,(4, 103, 1003) --Pk only in Table2
;
--Compare them
SELECT CASE
WHEN t1.PK IS NULL --This assumes that PK being NULL is due to the JOIN only!
THEN 'In Table2, and not in Table1'
WHEN t2.pk IS NULL --This assumes that PK being NULL is due to the JOIN only!
THEN 'In Table1, and not in Table2'
ELSE 'In both tables, but contents differ'
END AS ComparisonDescription
, t1.*
, t2.*
FROM Table1 t1
FULL JOIN Table2 t2
ON t1.pk = t2.pk
WHERE NOT EXISTS(
SELECT t1.* --IF not identically structured, select the common columns here
INTERSECT
SELECT t2.* --IF not identically structured, select the common columns here
)
;
Db<>Fiddle с примером