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ąć?
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. –
@KirkBroadhurst To nie dla mnie! Zobacz pełny test powyżej – podiluska
Ah Widzę, byłem zbyt szybki, aby przeczytać. Niesamowita odpowiedź dzięki! Nie wiedziałem, że mogę postawić tam warunkowe. –