1
votes

SQL MERGE: Est-il possible d'ignorer un MATCH?

Voici ma déclaration de fusion:

THEN UPDATE SET T.TranslationId = T.TranslationId

Je semble avoir des problèmes avec la section WHEN MATCHED . Sur la base de sur cette question et réponse , j'ai changé le WHEN MATCHED à:

MERGE PE_TranslationPhrase T
USING PE_TranslationPhrase_Staging S 
ON (T.CultureName = S.CultureName AND T.Phrase = S.Phrase)
WHEN MATCHED 
        THEN UPDATE SET T.TranslationId = T.TranslationId -- do nothing
WHEN NOT MATCHED BY TARGET
        THEN INSERT (TranslationId, CultureName, Phrase)
        VALUES (S.TranslationId, S.CultureName, S.Phrase);

Mais j'obtiens toujours cette erreur:

L'instruction MERGE a tenté de METTRE À JOUR ou DE SUPPRIMER la même ligne plusieurs fois. Cela se produit lorsqu'une ligne cible correspond à plus d'une ligne source. Une instruction MERGE ne peut pas UPDATE / DELETE la même ligne de la table cible plusieurs fois. Affinez la clause ON pour vous assurer qu'une ligne cible correspond à au plus une ligne source, ou utilisez la clause GROUP BY pour regrouper les lignes source.

Je comprends pourquoi. Sur la base de l'instruction ON , j'obtiens des correspondances en double. Mais ... je m'en fiche. Si un enregistrement de la table source existe déjà dans la table cible, je veux simplement ne rien faire. Ne mettez rien à jour du tout. Ignorez-le.

Est-ce possible?


2 commentaires

Pourquoi ne pas simplement omettre la section WHEN MATCHED ?


Il convient de mentionner que vous ne pouvez pas correspondre à NULL, vous devriez donc idéalement avoir des ISNULL autour de vos deux colonnes correspondantes (si elles ne sont pas déjà NOT NULL)


4 Réponses :


3
votes

Oh. Il s'avère que vous n'avez pas besoin de l'instruction «WHEN MATCHED». Je pensais que c'était nécessaire.

MERGE PE_TranslationPhrase T
USING PE_TranslationPhrase_Staging S 
ON (T.CultureName = S.CultureName AND T.Phrase = S.Phrase)
WHEN NOT MATCHED BY TARGET
        THEN INSERT (TranslationId, CultureName, Phrase)
        VALUES (S.TranslationId, S.CultureName, S.Phrase);


1 commentaires

Il convient de mentionner que vous ne pouvez pas correspondre à NULL, donc j'utiliserais ISNULL autour des deux colonnes de correspondance pour m'assurer que vous n'obtiendrez pas "Non apparié" lorsque les deux tables ont une valeur NULL dans la colonne de correspondance



0
votes

Malheureusement, ce qui ne peut pas être fait dans l'instruction MERGE pour omettre cette erreur. Mais j'ai résolu ce problème en générant une colonne d'identité (NON persistante) qui me permet d'ajouter une valeur unique à chaque enregistrement pour la source et la cible de la phrase et de comparer la forme. Quelque chose comme ceci:

ROW_NUMBER () OVER (PARTITION BY CultureName, Phrase ORDER BY CultureName, Phrase)


0 commentaires

1
votes

Si aucune mise à jour n'est en cours, avez-vous envisagé de simplement faire l'insertion en utilisant des lignes de PE_TranslationPhrase_Staging qui ne sont pas dans PE_TranslationPhrase?

Approche CTE :

INSERT INTO PE_TranslationPhrase (TranslationId, CultureName, Phrase)
SELECT 
TW.TranslationId, 
TW.CultureName, 
TW.Phrase
FROM (
SELECT 
    S.TranslationId, 
    S.CultureName, 
    S.Phrase
FROM PE_TranslationPhrase_Staging S 
LEFT JOIN PE_TranslationPhrase T on S.Phrase = T.Phrase and S.CultureName = T.CultureName
WHERE T.PHRASE IS NULL ) TW

Approche de sous-requête:

WITH CTE AS (
SELECT 
    S.TranslationId, 
    S.CultureName, 
    S.Phrase
FROM PE_TranslationPhrase_Staging S 
LEFT JOIN PE_TranslationPhrase T on S.Phrase = T.Phrase and S.CultureName = T.CultureName
WHERE T.PHRASE IS NULL
)

INSERT INTO PE_TranslationPhrase (TranslationId, CultureName, Phrase)
SELECT 
    TranslationId, 
    CultureName, 
    Phrase
FROM CTE


3 commentaires

Quelle serait la vitesse / le coût par rapport à une fusion?


Il y a plusieurs problèmes avec la fusion, dont certains sont liés au blocage, ce qui peut ne pas être un problème de toute façon puisque seule une insertion est effectuée. Le lien suivant les décrit plus en détail. En ce qui concerne les performances, je recommanderais d'exécuter un test pour les deux, puis d'examiner le plan d'exécution pour voir quels opérateurs logiques / physiques, index, etc., ont été utilisés et de quelle manière. Une sous-requête fonctionnerait peut-être mieux, je viens d'utiliser un CTE pour plus de clarté ici. mssqltips.com/sqlservertip/3074/…


Je suis sûr que vous connaissez les sous-requêtes, mais j'ai mis à jour mon message avec un exemple de ceci. Notez également qu'une sous-requête doit être aliasée (TW ci-dessus)



0
votes

Non, vous ne pouvez pas utiliser Merge ... When Matched ... dans les cas où il y a plusieurs correspondances et comme vous pouvez le découvrir, vous pouvez simplement supprimer le When Matched section. Cependant, si vous avez besoin de cette section pour la mise à jour , au lieu d'utiliser Merge , vous pouvez utiliser le code suivant:

update PE_TranslationPhrase
set  TranslationId = S.xxx
from
PE_TranslationPhrase T, PE_TranslationPhrase_Staging S
where T.CultureName = S.CultureName AND T.Phrase = S.Phrase


0 commentaires