In my Are you ready for SQL Server 2012 or are you still partying like it is 1999? post, I wrote about how you should start using SQL Server 2005 and SQL Server 2008 functionality now in order to prepare for SQL Server 2012. I still see tons of code that is written in the pre 2005 style and people still keep using those functions, procs and statements even though SQL Server 2005 and 2008 have much better functionality.
Today we are going to take a look at the OUTPUT clause as part of an INSERT, DELETE or UPDATE statement
In yesterday’s post SQL Advent 2011 Day 10: Upsert by using the Merge statement I already showed the OUTPUT clause in one or two examples, in today’s post I will only focus on the OUTPUT clause
First we need to create a test table
CREATE TABLE TestOutput (id int identity not null,SomeCol datetime)
GO
OUTPUT clause and insert statements
This code uses a Common Table Expression combined with the ROW_NUMBER function to generate 10 rows. We then use the dateadd function to generate 10 different days. We insert these 10 rows into the TestOutput output table, this table has an identity column and the id will be generated by SQL Server. We use the output statement to return the id as well as the SomeCol column values. The nice thing with the OUTPUT clause compared to the SCOPE_IDENTITY function is that the OUTPUT clause will return all values, SCOPE_IDENTITY only returns the last value generated
Run this code to see how it works
;WITH cte AS(
SELECT TOP 10 ROW_NUMBER() OVER(ORDER BY name) AS number
from sysobjects)
INSERT TestOutput
OUTPUT inserted.id,inserted.SomeCol
SELECT DATEADD(d,number,'20110101')
FROM CTE
Output
id SomeCol -- ----------------------- 1 2011-01-02 00:00:00.000 2 2011-01-03 00:00:00.000 3 2011-01-04 00:00:00.000 4 2011-01-05 00:00:00.000 5 2011-01-06 00:00:00.000 6 2011-01-07 00:00:00.000 7 2011-01-08 00:00:00.000 8 2011-01-09 00:00:00.000 9 2011-01-10 00:00:00.000 10 2011-01-11 00:00:00.000
If you check the table itself, you will see that you have exactly the same result as with the OUTPUT clause
SELECT * FROM TestOutput
id SomeCol -- ----------------------- 1 2011-01-02 00:00:00.000 2 2011-01-03 00:00:00.000 3 2011-01-04 00:00:00.000 4 2011-01-05 00:00:00.000 5 2011-01-06 00:00:00.000 6 2011-01-07 00:00:00.000 7 2011-01-08 00:00:00.000 8 2011-01-09 00:00:00.000 9 2011-01-10 00:00:00.000 10 2011-01-11 00:00:00.000
Instead of outputting the results right back, you can insert them in a table, temporary table or table variable, I am showing you how to do it with a table variable
DECLARE @TableVar table (id int,SomeDate datetime)
;WITH cte AS(
SELECT TOP 10 ROW_NUMBER() OVER(ORDER BY name) AS number
FROM sysobjects)
INSERT TestOutput
OUTPUT inserted.id,inserted.SomeCol INTO @TableVar
SELECT DATEADD(d,number,'20110101')
FROM cte
SELECT * FROM @TableVar
id SomeCol -- ----------------------- 11 2011-01-02 00:00:00.000 12 2011-01-03 00:00:00.000 13 2011-01-04 00:00:00.000 14 2011-01-05 00:00:00.000 15 2011-01-06 00:00:00.000 16 2011-01-07 00:00:00.000 17 2011-01-08 00:00:00.000 18 2011-01-09 00:00:00.000 19 2011-01-10 00:00:00.000 20 2011-01-11 00:00:00.000
OUTPUT clause and delete statements
To return the rows that were deleted, you would use deleted.ColumnName instead of inserted.ColumnName.
In the code block below, we are deleting all rows that are 0 if we divide them by 5, this is accomplished by using the modulo arithmetic operator which is % in T-SQL
DELETE TestOutput
OUTPUT deleted.id,deleted.SomeCol
WHERE id % 5 = 0
id SomeCol -- ----------------------- 5 2011-01-06 00:00:00.000 10 2011-01-11 00:00:00.000 15 2011-01-06 00:00:00.000 20 2011-01-11 00:00:00.000
As you can see we get 4 rows back, if you check what is in the table now, you will see that those 4 rows are missing.
OUTPUT clause and update statements
When you do an update statement, you will have the previous value (deleted) and the current value (inserted) available as part of the OUTPUT clause. Running the code below will output the value you had and the value that it got update to
UPDATE TestOutput
SET SomeCol = dateadd(yy,1,SomeCol)
OUTPUT deleted.id,deleted.SomeCol,inserted.SomeCol
WHERE id in(1,2)
id SomeCol SomeCol -- ----------------------- ----------------------- 1 2011-01-02 00:00:00.000 2012-01-02 00:00:00.000 2 2011-01-03 00:00:00.000 2012-01-03 00:00:00.000
That is all for today, come back tomorrow for another post