De manière très simplifiée, j'ai deux tables Source et Cible.
declare @Source table (SourceID int identity(1,2), SourceName varchar(50))
declare @Target table (TargetID int identity(2,2), TargetName varchar(50))
insert into @Source values ('Row 1'), ('Row 2')
Je voudrais déplacer toutes les lignes de @Source
a @Target
et connaître le TargetID
pour chaque SourceID
car il y a aussi les tableaux SourceChild
y TargetChild
qui doit être copié également et je dois ajouter la nouvelle TargetID
en TargetChild.TargetID
Colonne FK.
Il existe plusieurs solutions à ce problème.
- Utilisez une boucle while ou des curseurs pour insérer une rangée (RBAR) à la fois dans Target et utilisez la fonction
scope_identity()
pour remplir le FK deTargetChild
. - Ajouter une colonne temporaire à
@Target
et insérerSourceID
. Vous pouvez ensuite joindre cette colonne pour récupérer les données suivantesTargetID
pour le FK enTargetChild
. -
SET IDENTITY_INSERT OFF
para@Target
et de gérer vous-même l'attribution de nouvelles valeurs. Vous obtenez une plage que vous pouvez ensuite utiliser dansTargetChild.TargetID
.
Je n'aime pas beaucoup l'un d'entre eux. Celui que j'ai utilisé jusqu'à présent est le curseur.
Ce que j'aimerais vraiment faire, c'est utiliser l'option output
de l'instruction d'insertion.
insert into @Target(TargetName)
output inserted.TargetID, S.SourceID
select SourceName
from @Source as S
Mais il n'est pas possible
The multi-part identifier "S.SourceID" could not be bound.
Mais c'est possible avec une fusion.
merge @Target as T
using @Source as S
on 0=1
when not matched then
insert (TargetName) values (SourceName)
output inserted.TargetID, S.SourceID;
Résultat
TargetID SourceID
----------- -----------
2 1
4 3
Je voudrais savoir si vous l'avez utilisé ? Si vous avez des idées sur la solution ou si vous voyez des problèmes avec elle ? Cela fonctionne bien dans les scénarios simples, mais quelque chose de moche pourrait se produire lorsque le plan de requête devient vraiment compliqué en raison d'une requête source compliquée. Le pire scénario serait que les paires TargetID/SourceID ne correspondent pas.
Voici ce que dit MSDN à propos de la from_table_name
de la sortie clause.
Préfixe de colonne qui spécifie une table incluse dans la clause FROM d'une instruction DELETE, UPDATE ou MERGE, utilisée pour spécifier les lignes à mettre à jour ou à supprimer.
Pour une raison quelconque, ils ne disent pas "lignes à insérer, mettre à jour ou supprimer" mais seulement "lignes à mettre à jour ou supprimer".
Toute réflexion est la bienvenue et toute solution totalement différente du problème initial est très appréciée.
2 votes
La raison pour laquelle ils ne mentionnent pas l'insertion est que le nom de la table de départ (from_table_name) n'est pas valide dans les instructions d'insertion en entrée/sortie, tout comme le préfixe "deleted" (puisqu'aucune donnée existante ne peut être modifiée par une insertion).
12 votes
BTW : Adam Machanic couvre cette technique ici
0 votes
L'article du blog d'Adam Machanic sur la capacité de fusion est FANTASTIQUE ! Il a résolu exactement mon problème. Merci à Martin Smith de l'avoir publié. J'aimerais pouvoir donner plus qu'un simple +1
2 votes
Lien alternatif vers l'article d'Adam Machanic dataeducation.com/