Проблемы с оператором SQL Server MERGE
Таблица источников
Id, Name, Address
1 A #202
1 A #203
1 A #204
2 A #202
Таблица целей
Id, Name, Address
1 A NULL
После объединения
Id, Name, Address
1 A #202
2 A #202
Я использую этот SQL
create table #S (ID int, Name varchar(25) NULL, Address varchar(25) NULL)
create table #T (ID int, Name varchar(25) NULL, Address varchar(25) NULL)
INSERT #S values(1, 'A', '#202')
INSERT #S values(1, 'A', '#203')
INSERT #S values(1, 'A', '#203')
INSERT #S values(1, 'A', '#204')
INSERT #T values(1, 'A', NULL)
MERGE #T USING
(
Select id, name, address
from #S
) AS S(id,name,address)
on #T.id=S.id and #T.Name=S.Name
when not matched THEN
INSERT values(S.id,S.Name, S.Address)
when matched then
update set Address = S.Address;
GO
Select * from #T
GO
Select * from #S
GO
Это вызывает ошибку
Msg 8672, уровень 16, состояние 1, строка 18
Заявление MERGE пыталось ОБНОВИТЬ или УДАЛИТЬ одну и ту же строку более одного раза. Это происходит, когда целевая строка соответствует более чем одной строке источника. Оператор MERGE не может обновлять/удалять одну и ту же строку целевой таблицы несколько раз. Уточните предложение ON, чтобы гарантировать, что целевая строка соответствует не более одной исходной строке, или используйте предложение GROUP BY для группировки исходных строк.
Я хочу обновить строку в с помощью значения Address из любого из трех значений соответствия. Как это сделать?
Ответы
Ответ 1
Любое из четырех значений в #S
будет соответствовать вашему единственному значению целевой таблицы (все значения в #S имеют id = 1 и name = 'A' - поэтому все они соответствуют одной строке в целевом объекте), таким образом это значение будет обновляться четыре раза - это то, что говорит ошибка, и это абсолютно правильно.
Что вы действительно хотите здесь достичь?
Вы хотите установить адрес для первого из значений из исходной таблицы? Используйте предложение TOP 1
в вашем подзапросе:
MERGE #T
USING (SELECT TOP 1 id, name, address FROM #S) AS S
ON #T.id = S.id AND #T.Name = S.Name
WHEN NOT MATCHED THEN
INSERT VALUES(S.id,S.Name, S.Address)
WHEN MATCHED THEN
UPDATE SET Address = S.Address;
Вы хотите установить адрес в случайный элемент из значений из исходной таблицы? Используйте предложение TOP 1
и ORDER BY NEWID()
в вашем подзапросе:
MERGE #T
USING (SELECT TOP 1 id, name, address FROM #S ORDER BY NEWID()) AS S
ON #T.id = S.id AND #T.Name = S.Name
WHEN NOT MATCHED THEN
INSERT VALUES(S.id,S.Name, S.Address)
WHEN MATCHED THEN
UPDATE SET Address = S.Address;
Если вы сопоставляете четыре строки источника с одной целевой строкой, вы никогда не получите полезный результат - вам нужно знать, что вы действительно хотите.
Марк
Ответ 2
Удалите дубликат, используя
select R.*
from (SELECT Customer,Material,Received_date_time,
row_number() over (Partition by Customer, Material
order by Customer,Material,Received_date_time) as rn
from Customer_Table WHERE Status=0
) as R
where R.rn = 1
для слияния у вас не может быть дубликатов, поэтому вам всегда нужно подобрать последнюю версию