Can I grab the inserted IDs when doing multiple inserts? - sql-server

In my head this sounds improbable, but I'd like to know if I can do it:
INSERT INTO MyTable (Name)
VALUES ('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
SELECT INSERTED Name, ID FROM TheAboveQuery
Where ID is an auto-indexed column?
Just to clarify, I want to select ONLY the newly inserted rows.

Starting with SQL Server 2008 you can use OUTPUT clause with INSERT statement
DECLARE #T TABLE (ID INT, Name NVARCHAR(100))
INSERT INTO MyTable (Name)
OUTPUT INSERTED.ID, INSERTED.Name INTO #T
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
SELECT Name, ID FROM #T;
UPDATE: if table have no triggers
INSERT INTO MyTable (Name)
OUTPUT INSERTED.ID, INSERTED.Name
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');

Sure, you can use an IDENTITY property on your ID field, and create the CLUSTERED INDEX on it
ONLINE DEMO
create table MyTable ( ID int identity(1,1),
[Name] varchar(64),
constraint [PK_MyTable] primary key clustered (ID asc) on [Primary]
)
--suppose this data already existed...
INSERT INTO MyTable (Name)
VALUES
('First'),
('Second'),
('Third'),
('Fourth'),
('Fifth');
--now we insert some more... and then only return these rows
INSERT INTO MyTable (Name)
VALUES
('Sixth'),
('Seventh')
select top (##ROWCOUNT)
ID,
Name
from MyTable
order by ID desc
##ROWCOUNT returns the number of rows affected by the last statement executed. You can always see this in the messages tab of SQL Server Management Studio. Thus, we are getting the number of rows inserted and combining it with TOP which limits the rows returned in a query to the specified number of rows (or percentage if you use [PERCENT]). It is important that you use ORDER BY when using TOP otherwise your results aren't guaranteed to be the same
From my previous edited answer...
If you are trying to see what values were inserted, then I assume you are inserting them a different way and this is usually handled with an OUTPUT clause, TRIGGER if you are trying to do something with these records after the insert, etc... more information would be needed.

Related

How get last inserted ID in SQL Server 2012

How to get the last inserted ID in SQL Server 2012? It shows null for me.
One way would be
insert into your_table (...)
output INSERTED.ID
values (...)
Assuming table is
create table test
(
id int IDENTITY(1,1) PRIMARY KEY
, testData varchar(100) NOT NULL
)
this works
INSERT INTO dbo.Test (testData) VALUES ('test')
SELECT ##IDENTITY AS ID
as does this (better answer)
INSERT INTO dbo.Test (testData) VALUES ('test')
SELECT SCOPE_IDENTITY() AS ID
I don't have enough information to know why yours does not work. It is probably in the table structure? I would need more information to answer this.
We can use ##ROWCOUNT with SCOPE_IDENTITY() to get latest inserted ID in table as following:
INSERT INTO dbo.MyTable (...) VALUES (...)
SELECT ID
FROM [dbo].MyTable
WHERE ##ROWCOUNT > 0 AND ID = SCOPE_IDENTITY()

How to insert rows in another table based on insert in first table

If any insert happens in table A then,i need to insert the last inserted row into table B.
How can I do it by using ##rowcount.
I am trying below code.
create table table1
(
id int identity(1,1),
column1 nvarchar
)
create table table2
(
id int identity(1,1),
column1 nvarchar
)
Create procedure insert1
#column1 nvarchar
AS
Declare #t int,#column2 nvarchar
insert into table1 values(#column1)
select * from table1
set #t= (Select ##IDENTITY from table1)
Insert into table2 values (#t)
Please let me know how can i do the same by trigger.
You could write a trigger something like this:
CREATE TRIGGER trgTableAInsert
ON dbo.Table1
FOR INSERT
AS
INSERT INTO dbo.Table2(Column1)
SELECT Column1
FROM Inserted
Points to note:
a trigger is called once per statement, e.g. if your INSERT statement inserts 10 rows, the trigger is called once and Inserted contains those 10 newly inserted rows (do you want to insert all 10 of those into TableB?)
I would recommend to always use the schema prefix on tables (the dbo. part)
I would recommend to always explicitly specify the list of columns, both on an INSERT as well as a SELECT statement - don't omit those! (or you might run into messy and hard-to-debug issues when suddenly one of the tables changes)
MERGE INTO Table1 AS t1
USING MyTable ON 1=0 -- always generates "not matched by target"
WHEN NOT MATCHED BY TARGET THEN
-- INSERT into Table1:
INSERT (A, B, C) VALUES (t1.A, t1.B, t1.C)
--- .. and INSERT into Table2:
OUTPUT inserted.ID, MyTable.D, MyTable.E, MyTable.F
INTO Table2 (ID, D, E, F);

Retrieve original and new identities mapping from SELECT INSERT statement using OUTPUT clause

I have a table with two columns:
CREATE TABLE MyTable(
Id int IDENTITY(1,1) NOT NULL,
Name nvarchar(100) NOT NULL);
I want to duplicate the data using SELECT INSERT statement:
INSERT INTO MyTable (Name)
SELECT Name FROM MyTable
and here is the trickey part - I want to retrieve a mapping table between the original identity and the new identity:
DECLARE #idsMap TABLE (OriginalId int, NewId int)
I know I suppose to use the OUTPUT clause, but for some reason it doesn't work:
INSERT INTO MyTable (Name)
OUTPUT t.Id, INSERTED.Id INTO #idsMap (OriginalId, NewId)
SELECT Name FROM MyTable t
-- Returns error The multi-part identifier "t.Id" could not be bound.
Related questions:
can SQL insert using select return multiple identities?
Possible to insert with a Table Parameter, and also retrieve identity values?
It can be achieved using MERGE INTO and OUTPUT:
MERGE INTO MyTable AS tgt
USING MyTable AS src ON 1=0 --Never match
WHEN NOT MATCHED THEN
INSERT (Name)
VALUES (src.Name)
OUTPUT
src.Id,
inserted.Id
INTO #idsMap;
How about just adding a new column to MyTable? You can keep it around as long as you need to analysis or whatever. I have to say it seems a bit off to me to create a copy of the table but that is up to you to decide.
Something like this might work for you.
alter table MyTable
add OldID int null;
INSERT INTO MyTable (Name, OldID)
SELECT Name , Id
FROM MyTable t
select * from MyTable

Set A Field the same as ID (IDENTITY) in the insert

I have a Code (int) in my table, the ID is set to identity. How can I set a default value for my code to be filled by the same value az ID? I mean Identity.
You could use an after insert trigger:
create table TestTable (id int identity, col1 int)
go
create trigger TestTrigger on TestTable after insert
as begin
update TestTable
set col1 = id
where col1 is null
and id in (select id from inserted)
end
go
Test code:
insert TestTable default values
insert TestTable (col1) values (666)
insert TestTable default values
select * from TestTable
In general, I try to stay clear of triggers. In the long run using a stored procedure for insert is much more maintainable:
create procedure dbo.InsertTestRow(
#col1 int)
as
insert TestTable (col1) values (#col1)
if #col1 is null
begin
update TestTable
set col1 = id
where id = SCOPE_IDENTITY()
end
If it always has the same value - why don't you just drop that field. Otherwise it can be maintained with triggers (BEFORE INSERT one).
I'm looking for something in the
default value! If it is null it should
be filled with the same value as id
but if it is provided with some value,
it should keep that value
You could solve the issue by using coalesce in your queries instead.
create table T (ID int identity, ID2 int)
insert into T values (default)
insert into T values (null)
insert into T values (78)
select
ID,
coalesce(ID2, ID) as ID2
from T
Result
ID ID2
-- ---
1 1
2 2
3 78
Assuming your table's ID is an Identity column, you could consider using a constraint:
ALTER TABLE MyTable
ADD CONSTRAINT MyTableCodeDefault
DEFAULT IDENT_CURRENT('MyTable') FOR Code
This works for these use cases:
INSERT INTO MyTable DEFAULT VALUES
INSERT INTO MyTable ({columns NOT including 'Code'})
VALUES ({value list matching insert columns})
INSERT INTO MyTable (Code) VALUES (666)
INSERT INTO MyTable (Code) SELECT 8 UNION SELECT 13 UNION SELECT 21
But it does not work for bulk inserts:
INSERT INTO MyTable ({columns NOT including 'Code'})
SELECT {value list matching insert columns}
UNION
SELECT {value list matching insert columns}
UNION
SELECT {value list matching insert columns}
This restriction may seem onerous, but in my practical experience, it's rarely a problem. Most of the use cases I've encountered that need a default value involve user/UI 'convenience': don't force the user to pick a value if they don't want to.
OTOH, rarely do I encounter bulk insert situations where it's impractical to specify the value for the columns you're targeting.
You could use computed column, like this:
if object_id('TempTable') is not null drop table TempTable
create table TempTable (Id int identity(1,1), Code as Id)
insert into TempTable
default values
insert into TempTable
default values
insert into TempTable
default values
select * from TempTable
Of course if you have other columns, then you dont need default values:
if object_id('TempTable') is not null drop table TempTable
create table TempTable (Id int identity(1,1), Code as Id, SomethingElse int)
insert into TempTable (SomethingElse)
select 10 union all
select 11 union all
select 12
select * from TempTable
But, like zerkms said - why do you need two columns that are same?
If the field is an Identity field in SQL Server, the database engine will take care of its value. What we normally do is to read the record back (after inserting) to get to the generated Id.
EDIT: It sounds like you are trying to "override" the identity? If so, before you insert, run:
SET IDENTITY_INSERT [tableName] ON
You'll have to be careful not to insert a value that already exists. This can get tricky, though. So maybe consider removing the identity property altogether, and managing the default values yourself?

In SQL Server, how can I insert data into a table that has just one column which is of identity type?

In SQL Server, how can I insert data into a table that has just one column which is of identity type?
Such as insert into the following table t.
How can I write the insert statement?
CREATE TABLE t
(
id INT IDENTITY(1, 1) PRIMARY KEY
)
Great thanks.
To insert a single value
INSERT T DEFAULT VALUES
Or to insert multiple rows on SQL Server 2008+
MERGE INTO t
USING (SELECT TOP 100 *
FROM master..spt_values) T
ON 1 = 0
WHEN NOT MATCHED THEN
INSERT
DEFAULT VALUES;
To insert multiple rows in a single statement on previous versions would require the values to be entered explicitly, e.g. as below.
SET IDENTITY_INSERT t ON
INSERT INTO t
(id)
SELECT TOP 100
(SELECT ISNULL(MAX(id), 0) FROM t (TABLOCKX)) +
ROW_NUMBER() OVER (ORDER BY ##SPID)
FROM master.dbo.spt_values
SET IDENTITY_INSERT t OFF
If you want to continue inserting identity values, then use
INSERT YourTable DEFAULT VALUES;
If you want to insert explicit values then you can write
SET IDENTITY_INSERT YourTable ON
INSERT INTO YourTable (id) VALUES (5);
SET IDENTITY_INSERT YourTable OFF
Try:-
INSERT INTO t Values(NULL)

Resources