2009-09-16 10 views
14

Źródło TabelaProblemy z SQL Server oświadczenie MERGE

Id, Name, Address 
1 A  #202 
1 A  #203 
1 A  #204 
2 A  #202 

tabeli docelowej

Po Merge

Id, Name, Address 
1 A  #202 
2 A  #202 

Używam tego 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 

To powoduje błąd

Msg 8672, Level 16, State 1, wiersz 18
Oświadczenie MERGE próbował zaktualizować lub usunąć ten sam wiersz więcej niż raz. Dzieje się tak, gdy wiersz docelowy pasuje do więcej niż jednego wiersza źródłowego. Instrukcja MERGE nie może wielokrotnie aktualizować/usuwać tego samego wiersza tabeli docelowej. Popraw klauzulę ON, aby upewnić się, że wiersz docelowy pasuje do co najwyżej jednego wiersza źródłowego lub użyj klauzuli GROUP BY do zgrupowania wierszy źródłowych.

Chcę zaktualizować wiersz w A wartością adresu z dowolnej z trzech pasujących wartości. Jak to zrobić?

Odpowiedz

22

Każda z czterech wartości w będzie zgodna z wartością jednego wiersza tabeli docelowej (wszystkie wartości w #S mają identyfikator = 1 i nazwę = "A" - tak, że wszystkie pasują do pojedynczego wiersza w obiekcie docelowym), a zatem wartość będzie aktualizowana cztery razy - tak mówi błąd i jest absolutnie słuszna.

Co takiego naprawdę chcesz osiągnąć?

Czy chcesz ustawić adres na pierwszą wartość z tabeli źródłowej? Użyj TOP 1 klauzulę w swoim podselekcji:

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; 

Chcesz, aby ustawić adres do elementu losowego z wartościami z tabeli źródłowej? Użyj TOP 1 i ORDER BY NEWID() klauzulę w swoim podselekcji:

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; 

Jeśli dopasować cztery rzędy źródłowe do pojedynczego wiersza docelowego, nigdy nie uzyskać użyteczny wynik - trzeba wiedzieć, czego naprawdę chcą.

Marc

+0

Chcę zaktualizować wiersz A o wartości Adres z dowolnej z trzech pasujących wartości: –

+2

, ale jak określić, który z nich zastosować? – HLGEM

+2

Użyłem Row_Number jest zarówno źródłem, jak i celem (widok). Następnie kryteria dopasowania zawierały dodatkowy warunek, jeśli wartości rownumbers są równe wraz z (target.address isnull lub (t.address = s.address)) –

1

Zdjąć dupicate korzystając

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 

do seryjnej nie można mieć duplikaty, więc zawsze masz odebrać ostatnią

+0

W zależności od przypadku ma to więcej sensu. Może możesz dodać unikalne ograniczenie. –

Powiązane problemy