Two weeks ago I got an interesting questions. Two of my colleagues thought of a funny way to tease me, by asking me this question:
If we have an insert into table X, can we nest another insert into the query to fill table Y with the identity generated by insert X?
After thinking about this a few minutes, I told them I thought this was possible. Eventually I found a few spare minutes, and came up with this solution. In all honesty, this isn’t completely my solution. A few forums I came across mentioned this option, and I took those ideas and created my own solution.
So first, let’s create the 2 tables we need for this example:
DECLARE @T1 TABLE (ID INT IDENTITY(1,1), String VARCHAR(100)) DECLARE @T2 TABLE (ID_REF INT, String VARCHAR(100), Action VARCHAR(100))
So I’ve created T1 (table X in the question), and T2 (table Y). Let’s assume that T1 contains your product data, and for every product you insert, you want to insert a log-record into T2.
This can’t be done with actual nested inserts. If you want to do this, the easiest ways is to create a Stored Procedure (SP) that uses SCOPE_IDENTITY to retrieve the generated ID, and insert that into your second table. But because an SP isn’t always the best ways to do this, I wanted to see if I could transform it into a single query.
Since SQL Server 2008 we have the opportunity to use the MERGE statement. What the MERGE does is synchronize two tables by inserting, updating and deleting rows in the destination table, based on a set of rules and/or joins.
So, how would this statement look like? After some trial and error, I created this statement:
MERGE INTO @T1 T1 USING (SELECT -1 AS ID, 'This is a string' AS String) Q ON Q.ID = T1.ID WHEN NOT MATCHED BY TARGET THEN INSERT (String) VALUES ('This is a string...') OUTPUT inserted.ID, inserted.String, CONCAT('<<<<< Inserted in T1 @ ', CONVERT(DATE, GETDATE()) ,' >>>>>') INTO @T2;
As you can see the destination table is T1. This is the first table the record is inserted into, and the table that generates the identity. Because we only want to insert the record, and not update or delete anything, I only created a “WHEN NOT MATCHED BY TARGET” clause.
Because the ID columns don’t match, the record gets inserted into T1. After that, I use the OUTPUT clause of the merge statement to insert the same record (but with the generated identity) into T2. As a reference, I also insert the action-description that contains a date.
So as you can see, you can use nested inserts in SQL Server, only via another statement. But remember, this is just written to prove it’s possible in a single statement, and not for production usage. So if you decide to use this in production or on your system, consider your other options first!
Code samples:
Are nested Inserts possible.sql
