I am trying to copy a record in a table and change a few values with a stored procedure in SQL Server 2005. This is simple, but I also need to copy relationships in other tables with the new primary keys. As this proc is being used to batch copy records, I've found it difficult to store some relationship between old keys and new keys. Right now, I am grabbing new keys from the batch insert using OUTPUT INTO. ex:
INSERT INTO table
(column1, column2,...)
OUTPUT INSERTED.PrimaryKey INTO @TableVariable
SELECT column1, column2,...
Is there a way like this to easily get the old keys inserted at the same time I am inserting new keys (to ensure I have paired up the proper corresponding keys)?
I know cursors are an option, but I have never used them and have only heard them referenced in a horror story fashion. I'd much prefer to use OUTPUT INTO, or something like it.
INSERT
statements loading data into tables with anIDENTITY
column are guaranteed to generate the values in the same order as theORDER BY
clause in theSELECT
.From: The behavior of the IDENTITY function when used with SELECT INTO or INSERT .. SELECT queries that contain an ORDER BY clause
You can use this fact to match your old with your new identity values. First collect the list of primary keys that you intend to copy into a temporary table. You can also include your modified column values as well if needed:
Then do your
INSERT
with theOUTPUT
clause to capture your new ids into the table variable:Because of the
ORDER BY PrimaryKey
statement, you will be guaranteed that yourNew_ID
numbers will be generated in the same order as thePrimaryKey
field of the copied records. Now you can match them up by row numbers ordered by the ID values. The following query would give you the parings:If you need to track both old and new keys in your temp table, you need to cheat and use
MERGE
:Data setup:
And the replacement for your
INSERT
statement:And (actually needs to be in the same batch so that you can access the table variable):
Produces:
The reason you have to do this is because of an irritating limitation on the
OUTPUT
clause when used withINSERT
- you can only access theinserted
table, not any of the tables that might be part of aSELECT
.Related - More explanation of the
MERGE
abuse