Проверка различий между таблицами и внесение изменений

У меня есть эти две таблицы:

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)

Окончательный результат должен выглядеть так:

имя1 имя2 origin_date вар1 Дата окончания положение дел красный_1 красный 01.01.2010 ааа НУЛЕВОЙ активный красный_2 красный 01.01.2011 ббб 01.01.2020 неактивный синий_1 синий 01.01.2005 ссс 01.01.2020 неактивный зеленый_1 зеленый 01.01.2005 ддд 01.01.2020 неактивный фиолетовый_1 фиолетовый 01.01.2001 ффф 2020-01-03 неактивный розовый_1 розовый 01.01.2002 ггг 2020-01-03 неактивный оранжевый_1 апельсин 01.01.2012 ззз НУЛЕВОЙ активный

Я попытался написать код 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

Может кто-нибудь, пожалуйста, покажите мне, как это исправить?

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
1
0
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

После долгих переделок, я думаю, я мог бы найти подход, решающий эти проблемы:

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

Остальные условия также соблюдены:

  • активный всегда имеет значение end_date равное NULL, неактивный имеет ненулевое значение end_date
  • red_1 и Orange_1 не имеют конечной даты и активны.
Ответ принят как подходящий

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, и вы получите действительно хорошую строку после, за которой следует строка перед.

Другие вопросы по теме