Puis-je appliquer une clause where sur la cible dans une instruction MERGE?

J'ai une table cible contenant les éléments qui ont une IsActive drapeau, et je suis l'insertion et la mise à jour d'une table source à l'aide d'un MERGE déclaration. Si quelque chose existe dans la table source, alors qu'il est actif, et si ça ne marche pas, alors il n'est pas actif. La logique est assez simple:

  • si elle existe dans la source et la cible de la ligne doit avoir IsActive vrai
  • si elle existe uniquement dans la source, puis une nouvelle ligne doit être insérée à la cible, avec IsActive vrai
  • si elle existe uniquement dans la cible, puis la IsActive doit être définie sur false.

Tout très simple, à l'exception de la table cible a également une colonne discriminante SourceId qui se rapporte à la table source. Donc, pour une source donnée de la table, je ne veux MERGE contre les lignes correspondant à la SourceId.

(Mon normalisées table contient des lignes, identique à ce que les types de données à partir de plusieurs systèmes - je récupérer les données de ces systèmes individuellement et donc la nécessité de la fusion à partir d'une seule source à la fois)

Voici un exemple:

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

Ma première tentative a été d'inclure le AND t.[SourceId] = @SourceId dans la fusion condition, mais évidemment cela ne fonctionne pas - il est de restreindre les éléments à fusionner, mais pas la table cible. La ligne cible ID = 3 ne correspondent pas, et il sera réglé sur inactif, si oui ou non cette condition supplémentaire est inclus.

Le résultat final est que chaque fois que la procédure est exécutée pour un système source, tous les autres systèmes seront inactifs.

Ma solution pour l'instant est à exécuter le MERGE seulement pour MATCHED et NOT MATCHED BY TARGET, puis exécutez une ultérieure UPDATE pour les lignes sans correspondance

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

Est-il possible d'inclure cette condition de filtre dans la MERGE déclaration? Existe-il d'autres astuces pour arriver à cela?

OriginalL'auteur Kirk Broadhurst | 2012-06-27