У меня есть эти две таблицы:
CREATE TABLE old_table
(
name1 VARCHAR(20),
name2 VARCHAR(20),
origin_date DATE,
var1 VARCHAR(10),
end_date DATE,
status VARCHAR(10)
);
INSERT INTO old_table(name1, name2, origin_date, var1, end_date, status)
VALUES
('red_1', 'red', '2010-01-01', 'aaa', NULL, 'active'),
('red_2', 'red', '2011-01-01', 'bbb', '2020-01-01', 'inactive'),
('blue_1', 'blue', '2005-01-01', 'ccc', '2020-01-01', 'inactive'),
('green_1', 'green', '2005-01-01', 'ddd', '2020-01-01', 'inactive'),
('purple_1', 'purple', '2001-01-01', 'fff', NULL, 'active'),
('pink_1', 'pink', '2002-01-01', 'ggg', NULL, 'active');
CREATE TABLE new_table
(
name1 VARCHAR(20),
name2 VARCHAR(20),
origin_date DATE,
var1 VARCHAR(10),
today DATE
);
INSERT INTO new_table (name1, name2, origin_date, var1, today)
VALUES
('red_1', 'red', '2010-01-01', 'aaa', '2020-01-03'),
('orange_1', 'orange', '2012-01-01', 'zzz', '2020-01-01');
Сравнивая new_table с old_table:
end_date = new_table.today, status = inactive)end_date = NULL, status = active)end_date = NULL, status = active)Окончательный результат должен выглядеть так:
Я попытался написать код SQL, чтобы отразить эти требования:
SELECT
o.name1,
o.name2,
o.origin_date,
o.var1,
CASE
WHEN n.name1 IS NULL THEN o.end_date
ELSE NULL
END AS end_date,
CASE
WHEN n.name1 IS NULL THEN 'inactive'
ELSE 'active'
END AS status
FROM
old_table o
LEFT JOIN
new_table n ON o.name1 = n.name1
UNION ALL
SELECT
n.name1,
n.name2,
n.origin_date,
n.var1,
CASE
WHEN o.name1 IS NULL THEN NULL
ELSE n.today
END AS end_date,
'active' AS status
FROM
new_table n
LEFT JOIN
old_table o ON n.name1 = o.name1
WHERE
o.name1 IS NULL;
Проблема: end_date для purple_1 и pink_1 — это 01.01.2020, тогда как они должны быть 03.01.2020:
name1 name2 origin_date var1 end_date status
red_1 red 2010-01-01 aaa <NA> active
red_2 red 2011-01-01 bbb 2020-01-01 inactive
blue_1 blue 2005-01-01 ccc 2020-01-01 inactive
green_1 green 2005-01-01 ddd 2020-01-01 inactive
purple_1 purple 2001-01-01 fff 2020-01-01 inactive
pink_1 pink 2002-01-01 ggg 2020-01-01 inactive
orange_1 orange 2012-01-01 zzz <NA> active
Может кто-нибудь, пожалуйста, покажите мне, как это исправить?


После долгих переделок, я думаю, я мог бы найти подход, решающий эти проблемы:
WITH updated_old_table AS (
SELECT
old_table.name1,
old_table.name2,
old_table.origin_date,
old_table.var1,
CASE WHEN new_table.name1 IS NOT NULL AND old_table.status = 'active' THEN NULL
WHEN new_table.name1 IS NULL AND old_table.status = 'active' THEN (SELECT MAX(today) FROM new_table)
ELSE old_table.end_date END AS end_date,
CASE WHEN new_table.name1 IS NOT NULL THEN 'active'
WHEN new_table.name1 IS NULL AND old_table.status = 'active' THEN 'inactive'
ELSE old_table.status END AS status
FROM
old_table
LEFT JOIN
new_table ON old_table.name1 = new_table.name1
),
new_entries AS (
SELECT
name1,
name2,
origin_date,
var1,
NULL AS end_date,
'active' AS status
FROM
new_table
WHERE
name1 NOT IN (SELECT name1 FROM old_table)
)
SELECT * FROM updated_old_table
UNION ALL
SELECT * FROM new_entries;
Отсюда Purple_1 и Pink_1 имеют правильные даты окончания:
name1 name2 origin_date var1 end_date status
red_1 red 2010-01-01 aaa <NA> active
red_2 red 2011-01-01 bbb 2020-01-01 inactive
blue_1 blue 2005-01-01 ccc 2020-01-01 inactive
green_1 green 2005-01-01 ddd 2020-01-01 inactive
purple_1 purple 2001-01-01 fff 2020-01-03 inactive
pink_1 pink 2002-01-01 ggg 2020-01-03 inactive
orange_1 orange 2012-01-01 zzz <NA> active
Остальные условия также соблюдены:
AX — это следующая таблица BX — таблица «до» СОВЕТ: добавьте порядок по некоторому ключевому полю, одинаковому в обоих файлах, за которым следует 1
SELECT 'AFTER', A.* FROM
(SELECT * FROM AX
EXCEPT
SELECT * FROM BX) AS A
UNION
SELECT 'BEFORE', B.* FROM
(SELECT * FROM BX
EXCEPT
SELECT * FROM AX) AS B
СОВЕТ: добавьте порядок по некоторому ключевому полю, одинаковому в обоих файлах, за которым следует 1 пример order by productID, 1, и вы получите действительно хорошую строку после, за которой следует строка перед.