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
Vous devez vous connecter pour publier un commentaire.
De sorte que votre jeu de résultats doivent être
dans ce cas, votre instruction merge doit être
Test complet:
résultats...
3 2 0
pour la ligne en question. La raison en est que lorsque vous vous joignez àt.id = source.id
, il n'y a past
pour la ligne 3. Il est traité de la même façon que le rang 2 et marqué active.Il n'est pas pour moi! Voir le test complet ci-dessus
Ah je vois, j'ai été trop rapide à lire. Génial la réponse merci! Je ne savais pas que je pouvais mettre un conditionnel.
OriginalL'auteur podiluska