SQL Server Объединить несколько вставок, не соответствующих цели

У меня есть две таблицы для слияния, одна источник, а другая цель. Данные в Источник являются выходными данными из КТР.

Я пытаюсь вставить данные в Target, но у меня есть два условия для вставки данных в целевую таблицу.

Я использую Merge для обновления существующих данных и вставки новой строки. Целевая таблица включает исторические данные.

Статус в Источнике будет либо 1, либо 2, а статус в Цели будет либо R, либо S.

Вот пример процесса, который мне нужно выполнить.

Ниже приведены данные в исходной и целевой таблицах, а также несколько условий, которые мне нужно проверить.

Источник

| ID    |Name | Cond| Status |            
+-------+-----+-----+--------+
|   1   | A   | XYZ | 1      |

Цель

| ID    |Name | Cond| Status |  cdate          
+-------+-----+-----+--------+
|   1   | A   | XYZ | R      | 4/09/2019 4:34:28

Условие 1: теперь. Если в исходных данных есть какие-либо изменения, тогда source.status=2 и если target.id=source.id и target.status='R', то цель необходимо обновить с помощью исходных данных.

Источник

    | ID    |Name | Cond| Status |            
    +-------+-----+-----+--------+
    |   1   | B   | MNO | 2      |

Цель

    | ID    |Name | Cond| Status |   cdate         
    +-------+-----+-----+--------+
    |   1   | B   | MNO | R      | 4/09/2019 4:34:28

Условие 2: после выполнения одной хранимой процедуры target.status меняется на «S».

Теперь, если target.status = 'S' и source.status = 2 и (target.name != source.name or target.cond != source.cond), необходимо вставить новую строку в цель с target.status как «R».

Источник

    | ID    |Name | Cond| Status |            
    +-------+-----+-----+--------+
    |   1   | B   | MNO | 2      |

Цель

    | ID    |Name | Cond| Status |            
    +-------+-----+-----+--------+
    |   1   | A   | XYZ | S      | 4/09/2019 4:34:28
    |   1   | B   | MNO | R      | 6/09/2019 7:34:28

Для достижения результата я использовал MERGE, как показано ниже:

MERGE table_1 AS TARGET
USING data_from_cte AS SOURCE ON (TARGET.ID = SOURCE.ID AND Target.status = 'R') 

--WHEN RECORDS ARE MATCHED, UPDATE THE RECORDS IF THERE IS ANY CHANGE
WHEN MATCHED AND TARGET.STATUS = 'R' 
    THEN UPDATE 
             SET TARGET.name = SOURCE.name,
                 TARGET.cond = SOURCE.cond,

--WHEN NO RECORDS ARE MATCHED, INSERT THE INCOMING RECORDS FROM SOURCE TABLE TO TARGET TABLE
WHEN MATCHED AND TARGET.STATUS = 'S' AND source.status = 2 
             AND (target.name != source.name OR target.cond != source.cond)
    THEN INSERT (id, name, cond, status) 
         VALUES (SOURCE.ID, SOURCE.name, SOURCE.cond, 'R')

WHEN NOT MATCHED BY TARGET 
    THEN INSERT (id, name, cond, status) 
         VALUES (SOURCE.ID, SOURCE.name, SOURCE.cond, 'R');

Проблема здесь в том, что я не могу сравнить целевой столбец и исходный столбец в WHEN MATCHED условии MERGE оператора.

Как я могу решить эту проблему, используя оператор MERGE или оператор IF ... ELSE?

У нас здесь серьезная проблема: какой ключ у target? Изначально можно подумать, что это ID - но вы показываете случай, когда в целевой таблице есть две строки с идентификатором 1. Так скажите мне следующее: если у цели есть и S, и R для одного и того же идентификатора, должен ли он все еще вставлять еще одну строку с R ? Если да, мы можем найти способ, но это приведет к тому, что во время выполнения запроса будет вставляться все больше и больше R-строк. Если нет, то я сомневаюсь, что это можно сделать с помощью слияния, так как вам нужно читать несколько целевых строк, чтобы вывести одну результирующую строку - нужны подзапросы

George Menoutis 28.05.2019 00:01

Целевая таблица имеет столбец created_date и идентификатор, created_date в сочетании составляют первичный ключ. Также, если в статусе Target есть R, то строку следует обновить, а если есть S, то ее нужно вставить. Я много пробовал, но я потерпел неудачу. Не могли бы вы помочь?

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

Ответы 1

Ответ принят как подходящий

Вы кажетесь довольно близко, там. Вы немного запутались, потому что вам нужно было проверить существование строки S с помощью exists, и вы пытались сделать это с помощью синтаксиса слияния. Этого делать нельзя: можно только INSERT на WHEN NOT MATCHED BY TARGET. Попробуй это:

;MERGE table_1 AS TARGET
USING data_from_cte AS SOURCE -- (add WHERE source.status = 2 to your CTE)
ON (TARGET.ID = SOURCE.ID AND Target.status = 'R') 

--WHEN RECORDS ARE MATCHED, UPDATE THE RECORDS IF THERE IS ANY CHANGE
WHEN MATCHED AND TARGET.STATUS = 'R' AND operation='update' 
    THEN UPDATE 
             SET TARGET.name = SOURCE.name,
                 TARGET.cond = SOURCE.cond,

--WHEN NO RECORDS ARE MATCHED AND NO SAME S ROW EXISTS, INSERT THE INCOMING RECORDS FROM SOURCE TABLE TO TARGET TABLE
WHEN NOT MATCHED AND not exists(select 1 from table_1 t1 where t1.ID = SOURCE.ID AND t1.status = 'S' and t1.name = source.name and t1.cond = source.cond)
    THEN INSERT (id, name, cond, status) 
         VALUES (SOURCE.ID, SOURCE.name, SOURCE.cond, 'R')

Второе (WHEN NOT MATCHED...) условие изменено, но также не забудьте добавить пункт WHERE source.status = 2 в CTE.

Я получил ошибку, используя эту логику, поскольку идентификатор «TARGET.ID» не может быть связан. В предложении WHEN NOT MATCHED оператора MERGE разрешены только исходные столбцы и столбцы в области действия предложения.

Sql Programmer 28.05.2019 14:57

Я сделал это на бегу, надо было убрать префикс target., так как это самостоятельный вызов table1. Я изменил код, попробуйте еще раз.

George Menoutis 28.05.2019 16:24

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