Проблемы с оператором SQL Server MERGE - PullRequest
18 голосов
/ 16 сентября 2009

Исходная таблица

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 

Это вызывает ошибку

Сообщение 8672, уровень 16, состояние 1, строка 18
Инструкция MERGE пыталась ОБНОВИТЬ или УДАЛИТЬ одну и ту же строку более одного раза. Это происходит, когда целевая строка соответствует более чем одной исходной строке. Оператор MERGE не может ОБНОВИТЬ / УДАЛИТЬ одну и ту же строку целевой таблицы несколько раз. Уточните предложение ON, чтобы обеспечить соответствие целевой строки максимум одной исходной строке, или используйте предложение GROUP BY для группировки исходных строк.

Я хочу обновить строку в A значением Address из любого из трех совпадающих значений. Как это сделать?

Ответы [ 2 ]

24 голосов
/ 16 сентября 2009

Любое из четырех значений в #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;

Если вы сопоставите четыре исходные строки с одной целевой строкой, вы никогда не получите полезного результата - вам нужно знать, чего вы действительно хотите.

Марк

1 голос
/ 08 мая 2015

Удалите дубликат, используя

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

для слияния вы не можете иметь дубликаты, поэтому вам всегда нужно забрать самую последнюю

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...