2010-10-19 33 views
2

Je dois fusionner les données de 2 tables en une troisième (toutes ayant le même schéma) et générer un mappage des anciennes valeurs d'identité avec les nouvelles. L'approche évidente consiste à parcourir les tables source à l'aide d'un curseur, en insérant les anciennes et nouvelles valeurs d'identité en cours de route. Y a-t-il une meilleure façon (éventuellement orientée ensemble) de le faire?Meilleure façon de déplacer des données entre tables et générer des correspondances entre les anciennes et les nouvelles valeurs d'identité

MISE À JOUR: Un bit d'information supplémentaire: la table de destination contient déjà des données.

Répondre

3

Créez votre table de mappage avec une colonne IDENTITY pour le nouvel ID. Insérer à partir de vos tables source dans cette table, en créant votre mapping.

SET IDENTITY_INSERT ON pour votre table cible.

Insérez dans la table cible à partir de vos tables source jointes à la table de mappage, puis SET IDENTITY_INSERT OFF.

+0

Comment cela fonctionnerait-il si la table cible contient déjà des données? – Daniel

+1

lorsque vous créez l'identité sur la table de mappage, définissez le germe de sorte qu'il ne soit pas en conflit avec les données existantes. –

+1

[Cet article MSDN] (http://msdn.microsoft.com/en-us/library/ms175098.aspx) indique: 'Soyez prudent lorsque vous utilisez IDENT_CURRENT pour prédire la prochaine valeur d'identité générée. La valeur générée réelle peut être différente de IDENT_CURRENT plus IDENT_INCR en raison des insertions effectuées par d'autres sessions. Existe-t-il un moyen d'éviter de manière fiable les valeurs d'identité conflictuelles? – Daniel

1

Je pense que j'ajouterais temporairement une colonne supplémentaire à la nouvelle table pour contenir l'ancien ID. Une fois vos insertions terminées, vous pouvez extraire le mappage dans une autre table et supprimer la colonne.

+0

Cela suppose que je peux modifier le schéma de la table cible, ce que je peux, mais je suis curieux de savoir comment cela pourrait être résolu si ce n'est pas possible. – Daniel

+0

@Daniel: Essentiellement, j'utiliserais la même technique, mais au lieu de modifier la table cible, je créerais une table temporaire qui comprendrait le schéma de la table cible (y compris la colonne identité) plus l'ancienne colonne ID supplémentaire. Insérez dans la table temporaire, puis utilisez 'SET IDENTITY_INSERT NewTable ON' et insérez de la table temporaire dans votre nouvelle table. N'oubliez pas de "SET IDENTITY_INSERT NewTable OFF" lorsque vous avez terminé. –

+0

Vous ne pouviez pas rencontrer des valeurs d'identité conflictuelles lors de l'insertion dans la table cible? – Daniel

1

J'ai créé une table de mappage basée sur la clause OUTPUT de l'instruction MERGE. Non IDENTITY_INSERT requis. Dans l'exemple ci-dessous, il y a RecordImportQueue et RecordDataImportQueue et RecordDataImportQueue.RecordID est un FK à RecordImportQueue.RecordID. Les données dans ces tables de transfert doivent aller à Record et RecordData, et FK doit être conservé.

RecordImportQueue à enregistrement se fait en utilisant une instruction MERGE, la production d'une table de correspondance de son OUTPUT et RecordDataImportQueue va à l'aide d'un RecordDataINSERT d'un SELECT de la table source jointe à la table de correspondance.

DECLARE @MappingTable table ([NewRecordID] [bigint],[OldRecordID] [bigint]) 

MERGE [dbo].[Record] AS target 
USING (SELECT [InstanceID] 
      ,RecordID AS RecordID_Original 
      ,[Status] 
     FROM [RecordImportQueue] 
     ) AS source 
ON (target.RecordID = NULL) -- can never match as RecordID is IDENTITY NOT NULL. 
WHEN NOT MATCHED THEN 
    INSERT ([InstanceID],[Status]) 
    VALUES (source.[InstanceID],source.[Status]) 
    OUTPUT inserted.RecordID, source.RecordID_Original INTO @MappingTable; 

Après cela, vous pouvez insérer les enregistrements dans une table de référence comme folows:

INSERT INTO [dbo].[RecordData] 
    ([InstanceID] 
    ,[RecordID] 
    ,[Status]) 
SELECT [InstanceID] 
    ,mt.NewRecordID -- the new RecordID from the mappingtable 
    ,[Status] 
FROM [dbo].[RecordDataImportQueue] AS rdiq 
JOIN @MappingTable AS mt 
ON rdiq.RecordID = mt.OldRecordID 

Bien que longtemps après le message original, j'espère que cela peut aider d'autres personnes, et je suis curieux Tous les commentaires.

+0

Bon tour, cela fonctionne parfaitement! – SteveSmithSQL