SQL Server list of insert identities - sql-server

I have a table with an autoincrement id that I am doing a
INSERT INTO ( ... ) SELECT ... FROM ...
Is there a way for me to get the list of id's that have been inserted?
I was thinking I could get the max id before the insert then after and assuming everything in between is new, but then if a row gets inserted from somewhere else I could run into problems. Is there a proper way to do this?
I am using SQL Server 2005

Use the output clause.
DECLARE #InsertedIDs table(ID int);
INSERT INTO YourTable
OUTPUT INSERTED.ID
INTO #InsertedIDs
SELECT ...

Create a table variable and then use the OUTPUT clause into the table variable.
OUTPUT inserted.NameOfYourColumnId INTO tableVariable
Then you can SELECT from your table variable.

Related

SQL Server - Insert record count into table

I need to execute this script monthly to load a record count into at table:
select count([BG_BUG_ID])
from [uc_maint_maintenance_db].[td].[BUG]
I created a table with one column to contain the numeric output:
CREATE TABLE [dbo].[BG_BUG_ID]
(
[BG_BUD_ID_COUNT] [numeric](18, 0) NULL
)
I receive an error on the select statement when I execute the script below:
INSERT INTO [AdminDB].[dbo].[BG_BUG_ID](count)
VALUES (SELECT COUNT([BG_BUG_ID])
FROM [uc_maint_maintenance_db].[td].[BUG])
What am I doing wrong? The select runs fine on its own. Any ideas are greatly appreciated!
I need to make this insert into a stored procedure.
Remove values:
Insert into [AdminDB].[dbo].[BG_BUG_ID](BG_BUD_ID_COUNT)
select count([BG_BUG_ID])
from [uc_maint_maintenance_db].[td].[BUG]
You have mentioned wrong column name count instead of
BG_BUD_ID_COUNT.
Remove keyword values.
Try like below
INSERT INTO [AdminDB].[dbo].[BG_BUG_ID](BG_BUD_ID_COUNT)
SELECT COUNT([BG_BUG_ID])
FROM [uc_maint_maintenance_db].[td].[BUG]
INSERT INTO [AdminDB].[dbo].[BG_BUG_ID]
SELECT COUNT([BG_BUG_ID])
FROM [uc_maint_maintenance_db].[td].[BUG]

Output insert and table values when doing insert into

I'm inserting into a table in MS SQL Server 2008 (it's rather a copy of values from the same table) and want to get the output values for the insert. I want to get the id value of the select statement (t.id in the example below), the INSERTED.id works just fine
create table tmp.tbl_inserted (fromId int, toId int)
INSERT INTO mytable (name)
OUTPUT t.id, INSERTED.id INTO tmp.tbl_inserted
SELECT t.name FROM mytable t
Thanks in advance
You can't do it directly from an INSERT:
from_table_name
Is a column prefix that specifies a table included in the FROM clause of a DELETE, UPDATE, or MERGE statement that is used to specify the rows to update or delete.
Note that INSERT isn't mentioned.
What you have to do instead is cheat and use a MERGE:
MERGE INTO mytable m
USING (name,id FROM mytable) t ON 1=0
WHEN NOT MATCHED THEN INSERT (name) VALUES (t.name)
OUTPUT t.id, INSERTED.id INTO tmp.SizeCurveGroup_inserted
;

Copy table rows using OUTPUT INTO in SQL Server 2005

I have a table which I need to copy records from back into itself. As part of that, I want to capture the new rows using an OUTPUT clause into a table variable so I can perform other opertions on the rows as well in the same process. I want each row to contain its new key and the key it was copied from. Here's a contrived example:
INSERT
MyTable (myText1, myText2) -- myId is an IDENTITY column
OUTPUT
Inserted.myId,
Inserted.myText1,
Inserted.myText2
INTO
-- How do I get previousId into this table variable AND the newly inserted ID?
#MyTable
SELECT
-- MyTable.myId AS previousId,
MyTable.myText1,
MyTable.myText2
FROM
MyTable
WHERE
...
SQL Server barks if the number of columns on the INSERT doesn't match the number of columns from the SELECT statement. Because of that, I can see how this might work if I added a column to MyTable, but that isn't an option. Previously, this was implemented with a cursor which is causing a performance bottleneck -- I'm purposely trying to avoid that.
How do I copy these records while preserving the copied row's key in a way that will achieve the highest possible performance?
I'm a little unclear as to the context - is this in an AFTER INSERT trigger.
Anyway, I can't see any way to do this in a single call. The OUTPUT clause will only allow you to return rows that you have inserted. What I would recommend is as follows:
DECLARE #MyTable (
myID INT,
previousID INT,
myText1 VARCHAR(20),
myText2 VARCHAR(20)
)
INSERT #MyTable (previousID, myText1, myText2)
SELECT myID, myText1, myText2 FROM inserted
INSERT MyTable (myText1, myText2)
SELECT myText1, myText2 FROM inserted
-- ##IDENTITY now points to the last identity value inserted, so...
UPDATE m SET myID = i.newID
FROM #myTable m, (SELECT ##IDENTITY - ROW_NUMBER() OVER(ORDER BY myID DESC) + 1 AS newID, myID FROM inserted) i
WHERE m.previousID = i.myID
...
Of course, you wouldn't put this into an AFTER INSERT trigger, because it will give you a recursive call, but you could do it in an INSTEAD OF INSERT trigger. I may be wrong on the recursive issue; I've always avoid the recursive call, so I've never actually found out. Using ##IDENTITY and ROW_NUMBER(), however, is a trick I've used several times in the past to do something similar.

SQL Server: is it possible to get recently inserted identity column value without table variable

Let's say I have a table
my_table(id int identity(1,1) not null primary key, data varchar(100))
I want to write a procedure that inserts a new row into that table and returns id.
I tried
DECLARE #new_id INT;
SELECT #new_id = id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id)
That code doesn't work (I got "A nested INSERT, UPDATE, DELETE, or MERGE statement is not allowed in a SELECT statement that is not the immediate source of rows for an INSERT statement."). However, if I use a table variable, I can do
DECLARE #new_id INT;
DECLARE #tmp_table TABLE(int id);
INSERT INTO #tmp_table
SELECT id FROM
(
INSERT INTO my_table(data) OUTPUT inserted.id VALUES ('test')
) as NewVal(id);
// OR
INSERT INTO my_table(data) OUTPUT inserted.id INTO #tmp_table VALUES ('test') ;
SELECT #new_id = id FROM #tmp_table;
Is it possible to achieve the same functionality without using table variable ?
UPDATE
Thanks for quick responses, +1 to everyone for solution with SCOPE_IDENTITY.
That's probably my fault, I should have asked the question clearly - I do use MERGE (an example would be much longer, so I posted INSERT instead) , not INSERT so SCOPE_IDENTITY doesn't really work for me.
A bit shorter version than nesting in a insert statement is using output...into.
declare #tmp_table table(actiontaken nvarchar(10), id int);
merge my_table
using (values ('test')) as S(data)
on 0=1
when not matched then
insert (data) values (S.data)
output $action, inserted.id into #tmp_table;
I do believe that you should use a table variable from the merge. The output may contain more than one row.
Yes, you can just return SCOPE_IDENTITY after the insert (this is safer than ##IDENTITY due to the scoping differences).
i.e.
INSERT my_table (data) VALUES ('test')
SELECT SCOPE_IDENTITY()
SELECT SCOPE_IDENTITY() will get the last inserted identity value in the scope.
If you use
select ##identity
you will get the last value entered into the identity column from anywhere.
If you want the value entered into the column from the script that just ran, you should use
select SCOPE_IDENTITY()
If you just want the last value inserted into the identity column for a given table from any statement in any session, you should use
select IDENT_CURRENT('tablename')
select ##identity or select SCOPE_IDENTITY() will return the value you're looking for

SQL Server pagination of a result set

I have a very meaty stored procedure in a SQL Server 2000 DB which returns a single resultset. I don't want to (not allowed to) touch the original SP but would like add pagination to the returned records.
Is it possible to wrap this SP with another that takes the returned resultset and only gives me rows X to Y ?
create procedure ProcWrap
as
declare #T table (ID int, Name nvarchar(50))
insert into #T
exec ProcToWrap
select *
from #T
where ID < 10
Edit 1
Don't have SQL Server 2000 to test on and I don't remember if table variables where available then. Here is a procedure using a temp table instead. Added a RowNum identity column that you can use for pagination.
create procedure ProcWrap2
as
create table #T (RowNum int identity, ID int, Name nvarchar(50))
insert into #T
exec ProcToWrap
select *
from #T
where RowNum between 10 and 19
drop table #T
Edit 2
Output from ProcToWrap in this case is columns ID and Name. RowNum is generated automatically.
Get the results from the SP and put them in a temporary table, then you can select X results from that table.
As others have said you will have to put the results of the procedure in a temp table then select the rows you want from that.
To get a set of rows from your results you need to use the ROW_NUMER() function:
SELECT
ROW_NUMBER() OVER (ORDER BY ID) AS row_number, *
FROM
Your_Temp_Table
WHERE row_number BETWEEN 11 AND 20 -- For the second page of results with 10 per page.
EDIT: Just realised you are using SQL Server 2000 which does not have ROW_NUMBER(), sorry
EDIT2: Since you are storing the results of the query in a temp table you can add an incrementing integer field to that result set and use that as a simulation for the ROW_NUMBER() in order to select the row you need.
EDIT3: Here's a link to an article discussing pagination in SQL Server 2000

Resources