2012-06-27 3 views
11

Mam tabelę docelową zawierającą elementy, które mają flagę IsActive i wstawiam i aktualizuję z tabeli źródłowej za pomocą instrukcji MERGE. Jeśli coś istnieje w tabeli źródłowej, to jest aktywne, a jeśli nie, to nie jest aktywne. Logika jest bardzo prosta:Czy mogę zastosować klauzulę WHERE na celu w instrukcji MERGE?

  • jeśli istnieje w źródle, a cel rząd powinien mieć IsActive prawdziwą
  • jeśli istnieje tylko w źródle wtedy nowy rząd powinien być włożony do celu, z IsActive true
  • jeśli istnieje tylko w celu, wówczas IsActive należy ustawić na false.

Wszystkie bardzo proste, z wyjątkiem tabeli docelowej, również kolumna dyskryminacyjna SourceId, która odnosi się do tabeli źródłowej. Tak więc dla danej tabeli źródłowej chcę tylko MERGE w stosunku do wierszy z odpowiednimi SourceId.

(My znormalizowana tabela zawiera rzędy identycznych typów danych z wielu systemów - odzyskać dane z tych systemów indywidualnie, a tym samym konieczność scalenia z jednego źródła na raz)

Oto przykład:

IF OBJECT_ID('tempdb..#target') IS NOT NULL DROP TABLE #target  
IF OBJECT_ID('tempdb..#source') IS NOT NULL DROP TABLE #source 

CREATE TABLE #target (Id INT, SourceId INT, IsActive BIT) 
INSERT #target VALUES (1, 1, 0) 
INSERT #target VALUES (2, 1, 1) 
INSERT #target VALUES (3, 2, 1) 

CREATE TABLE #source (Id INT)  
INSERT #source VALUES (1) 
INSERT #source VALUES (4) 

DECLARE @SourceId INT = 1;  
SELECT * FROM #target 

MERGE INTO #target t 
USING 
(
    SELECT [Id] FROM #source 
) AS s 
ON t.[Id] = s.[Id] AND t.[SourceId] = @SourceId 
WHEN MATCHED THEN UPDATE SET [IsActive] = 1 
WHEN NOT MATCHED BY TARGET THEN INSERT VALUES ([Id], @SourceId, 1) 
WHEN NOT MATCHED BY SOURCE THEN UPDATE SET [IsActive] = 0; 

SELECT * FROM #target 

Pierwsza próba polegała na dodaniu AND t.[SourceId] = @SourceId do warunku scalenia, ale oczywiście to nie zadziała - ogranicza elementy do scalenia, ale nie do tabeli docelowej. Identyfikator wiersza docelowego = 3 nie będzie zgodny, więc zostanie ustawiony na nieaktywny, niezależnie od tego, czy ten dodatkowy warunek zostanie uwzględniony.

Końcowym rezultatem jest to, że za każdym razem, gdy zostanie uruchomiona procedura dla systemu źródłowego, wszystkie inne systemy zostaną ustawione jako nieaktywne.

Moje rozwiązanie jakim jest uruchomienie MERGE tylko dla MATCHED i NOT MATCHED BY TARGET, a następnie uruchomić kolejny UPDATE dla niedopasowanych wierszy

UPDATE #target 
SET [IsEnabled] = 0 
WHERE [SourceId] = @SourceId 
AND [ID] NOT IN (SELECT [ID] FROM #source) 

Czy istnieje jakiś sposób, aby włączyć ten warunek filtra w rachunku MERGE? Czy istnieją inne sprytne sposoby, aby to osiągnąć?

Odpowiedz

7

Więc twój zestaw wynik powinien być

1 1 1 
2 1 0  
3 2 1 
4 1 1 

, w którym to przypadku oświadczenie scalania powinny być

merge #target as t 
using #source as source 
on (t.id=source.id) 
when matched then update set isactive=1 
when not matched by target then insert values (id, @sourceid,1) 
when not matched by source and [email protected] then update set isactive=0 

pełny test:

CREATE TABLE #target (Id INT, SourceId INT, IsActive BIT)  
INSERT #target VALUES (1, 1, 0) 
INSERT #target VALUES (2, 1, 1) 
INSERT #target VALUES (3, 2, 1) 

CREATE TABLE #source (Id INT)  
INSERT #source VALUES (1) 
INSERT #source VALUES (4) 

DECLARE @SourceId INT 
select @SourceId = 1;  

merge #target as t 
using #source as source 
on (t.id=source.id) 
when matched then update set isactive=1 
when not matched by target then insert values (id, @sourceid,1) 
when not matched by source and [email protected] then update set isactive=0; 


SELECT * FROM #target 

drop table #target; 
drop table #source 

wyników ...

Id   SourceId IsActive 
----------- ----------- -------- 
1   1   1 
2   1   0 
3   2   1 
4   1   1 
+0

Jeśli spróbujesz, zobaczysz, że daje '3 2 0' dla danego wiersza. Powodem jest to, że kiedy dołączasz do 't.id = source.id', nie ma' t' dla wiersza 3. Jest on traktowany tak samo jak wiersz 2 i zaznaczony jako aktywny. –

+1

@KirkBroadhurst To nie dla mnie! Zobacz pełny test powyżej – podiluska

+0

Ah Widzę, byłem zbyt szybki, aby przeczytać. Niesamowita odpowiedź dzięki! Nie wiedziałem, że mogę postawić tam warunkowe. –