This question already has answers here:
How to get last inserted id?
(16 answers)
Closed 10 years ago.
I want to get the new created ID when you insert a new record in table.
I read this: http://msdn.microsoft.com/en-us/library/ms177564.aspx but it needs to create temporary table.
I want to return the ID after executing INSERT statement (assuming executing just one INSERT).
Example:
1 Joe Joe
2 Michael Mike
3 Zoe Zoe
When executing an INSERT statement, I want to return the created ID, means 4.
Can tell me how to do that using SQL statement or it is not possible ?
If your SQL Server table has a column of type INT IDENTITY (or BIGINT IDENTITY), then you can get the latest inserted value using:
INSERT INTO dbo.YourTable(columns....)
VALUES(..........)
SELECT SCOPE_IDENTITY()
This works as long as you haven't inserted another row - it just returns the last IDENTITY value handed out in this scope here.
There are at least two more options - ##IDENTITY and IDENT_CURRENT - read more about how they works and in what way they're different (and might give you unexpected results) in this excellent blog post by Pinal Dave here.
Assuming a simple table:
CREATE TABLE dbo.foo(ID INT IDENTITY(1,1), name SYSNAME);
We can capture IDENTITY values in a table variable for further consumption.
DECLARE #IDs TABLE(ID INT);
-- minor change to INSERT statement; add an OUTPUT clause:
INSERT dbo.foo(name)
OUTPUT inserted.ID INTO #IDs(ID)
SELECT N'Fred'
UNION ALL
SELECT N'Bob';
SELECT ID FROM #IDs;
The nice thing about this method is (a) it handles multi-row inserts (SCOPE_IDENTITY() only returns the last value) and (b) it avoids this parallelism bug, which can lead to wrong results, but so far is only fixed in SQL Server 2008 R2 SP1 CU5.
You can use:
SELECT IDENT_CURRENT('tablename')
to access the latest identity for a perticular table.
e.g. Considering following code:
INSERT INTO dbo.MyTable(columns....) VALUES(..........)
INSERT INTO dbo.YourTable(columns....) VALUES(..........)
SELECT IDENT_CURRENT('MyTable')
SELECT IDENT_CURRENT('YourTable')
This would yield to correct value for corresponding tables.
It returns the last IDENTITY value produced in a table, regardless of the connection that created the value, and regardless of the scope of the statement that produced the value.
IDENT_CURRENT is not limited by scope and session; it is limited to a specified table. IDENT_CURRENT returns the identity value generated for a specific table in any session and any scope.
Related
CREATE TABLE Table1 :
Id int IDENTITY(1,1),
PK_Column1 nvarchar(50) Primary Key.
INSERT INTO Table1 (PK_Column1) VALUES ('Name'+Id)
Result:
Id PK_Column1
1 Name1
Is this possible? Or do I need to manage the Id column myself for this to work?
From the documentation:
After an INSERT, SELECT INTO, or bulk copy statement completes, ##IDENTITY contains the last identity value generated by the statement.
This applies to all the other identity checkers.
You should probably write a little SP to update the record immediately after your insert if this is what you need. Given that your primary_key appears to be some unusual composite of the ID and a varchar, you would also be best reviewing your data model.
It's important to note the difference with ##IDENTITY and SCOPE_IDENTITY():
##IDENTITY and SCOPE_IDENTITY return the last identity value generated in any table in the current session. However, SCOPE_IDENTITY returns the value only within the current scope; ##IDENTITY is not limited to a specific scope.
My application inserts some data into a table.
insert into this_Table (id, value, value)
I have then created a trigger that does a simple insert, into a different table with a primary key.
insert into temp_wc_triggertest values ('test', GETDATE())
My problem is then, the application tries to look for scope_identity, from the first insert. However, it gets overwritten by the trigger, which changes the scope identity to the primary key of temp_wc_triggertest.
How can I stop the trigger overwriting scope_identity?
I realise there is not much code to help here, which would normally be classed as a bad question, but I don't have permission to access to the full application code at the moment, so I am hoping this is answerable as is.
This is on SQL Server 2008 R2
EDIT: I have looked at the code, and it does use scope_identity
Your client is most certainly using ##IDENTITY instead of SCOPY_IDENTITY()
Here is a SQL Fiddle with some code you can test on.
SQL Fiddle
MS SQL Server 2008 Schema Setup:
create table T1(ID int identity(1,1));
create table T2(ID int identity(1000, 1));
go
create trigger tr_T1 on T1 for insert
as
insert into T2 default values;
Query:
insert into T1 default values
select ##identity as "##identity",
scope_identity() as "scope_identity()"
Results:
| ##IDENTITY | SCOPE_IDENTITY() |
---------------------------------
| 1000 | 1 |
If you are using SCOPE_IDENTIY correctly, you may also be experiencing a known bug - http://connect.microsoft.com/SQLServer/feedback/details/328811
MS has fixed it permanently for 2012, and has patches available for 2008 and 2008R2.
The reason for it overwriting scope identity is still not clear, it could possibly be related to the bug mentioned. However a fix was found:
A temporary table was created "temp_wc"
Then at the end of the trigger, identity insert was switched on for that table, and an insert was done, for the ID that we want to keep after the trigger has fired. This method can be thought of as overwriting the overwritten scope identity again.
SET IDENTITY_INSERT ON
INSERT INTO temp_wc VALUES (#ID, 'fix scope identity error')
This may help anyone in the future with this issue:
https://learn.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-2017
You may need to patch SQL Server, as it looks like the SCOPE_IDENTITY should return the inserted ID on the table that is actually receiving the primary insert, not the SQL trigger insert statements.
From the Microsoft docs for SQL Server 2017 (in case link is broken):
Remarks SCOPE_IDENTITY, IDENT_CURRENT, and ##IDENTITY are similar
functions because they return values that are inserted into identity
columns.
IDENT_CURRENT is not limited by scope and session; it is limited to a
specified table. IDENT_CURRENT returns the value generated for a
specific table in any session and any scope. For more information, see
IDENT_CURRENT (Transact-SQL).
SCOPE_IDENTITY and ##IDENTITY return the last identity values that are
generated in any table in the current session. However, SCOPE_IDENTITY
returns values inserted only within the current scope; ##IDENTITY is
not limited to a specific scope.
For example, there are two tables, T1 and T2, and an INSERT trigger is
defined on T1. When a row is inserted to T1, the trigger fires and
inserts a row in T2. This scenario illustrates two scopes: the insert
on T1, and the insert on T2 by the trigger.
Assuming that both T1 and T2 have identity columns, ##IDENTITY and
SCOPE_IDENTITY return different values at the end of an INSERT
statement on T1. ##IDENTITY returns the last identity column value
inserted across any scope in the current session. This is the value
inserted in T2. SCOPE_IDENTITY() returns the IDENTITY value inserted
in T1. This was the last insert that occurred in the same scope. The
SCOPE_IDENTITY() function returns the null value if the function is
invoked before any INSERT statements into an identity column occur in
the scope.
Failed statements and transactions can change the current identity for
a table and create gaps in the identity column values. The identity
value is never rolled back even though the transaction that tried to
insert the value into the table is not committed. For example, if an
INSERT statement fails because of an IGNORE_DUP_KEY violation, the
current identity value for the table is still incremented.
Another link here:
http://www.sqlbadpractices.com/how-not-to-retrieve-identity-value/
The problem with this code is that you may not retrieve the identity
value that you inserted. For example, if there is a trigger on the
table performing an insert on another table, you will get the last
created identity value. Even if you never create any trigger, you may
get skewed results with replicated tables since SQL Server creates his
own replication triggers.
Use SELECT IDENT_CURRENT(‘tablename’)
"It returns the last IDENTITY value produced in a table, regardless of the connection that created the value, and regardless of the scope of the statement that produced the value."
See this link for details.
http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
This is my table.
Ticket(id int auto_increment,name varchar(50));
after inserting into this table i want send id and name to mail..
how can i get the last Inserted value.
help to solve this...
Look into: Scope_identity
SCOPE_IDENTITY()
The table which is having Identity Property from that table we can get the last inserted record id will be like this
SELECT SCOPE_IDENTITY()
OR
But this is not a safe technique:
SELECT MAX(Id) FROM Ticket
OR
This is also not a safe technique:
SELECT TOP 1 Id FROM Ticket ORDER BY Id DESC
You should use SCOPE_IDENTITY() to get last primary key inserted value on your table. I guess it should be the ID value. Once you have it, do a SELECT using this ID and there you have it.
There is also ##IDENTITY but there are some differences using one or the another that could lead to inaccuracies on the values.
Check these detailed articles for more insights, a detailed description on how to use them, why they are different and some demo code:
For the last time, NO, you can't trust IDENT_CURRENT()
sql server identity vs scope_identity vs ident_current retrieve last inserted identity of record
For SQL Server before 2008 R2 Service Pack 1 (Link):
You may receive incorrect values when using SCOPE_IDENTITY() and
##IDENTITY
In that case, the OUTPUT clause is the safest mechanism:
DECLARE #InsertedRows AS TABLE (Id int)
DECLARE #NewId AS INT
INSERT INTO HumanResources.Employees
( /* column names */)
OUTPUT Inserted.Id INTO #InsertedRows
VALUES (/* column values */)
SELECT #NewId = Id FROM #InsertedRows
add auto increement Field in your table like.... index (INT,AUTO INCREEMENT)
then before insert or any operation done c get your last record by getting max(index)
I'm trying to get a the key-value back after an INSERT-statement.
Example:
I've got a table with the attributes name and id. id is a generated value.
INSERT INTO table (name) VALUES('bob');
Now I want to get the id back in the same step. How is this done?
We're using Microsoft SQL Server 2008.
No need for a separate SELECT...
INSERT INTO table (name)
OUTPUT Inserted.ID
VALUES('bob');
This works for non-IDENTITY columns (such as GUIDs) too
Use SCOPE_IDENTITY() to get the new ID value
INSERT INTO table (name) VALUES('bob');
SELECT SCOPE_IDENTITY()
http://msdn.microsoft.com/en-us/library/ms190315.aspx
INSERT INTO files (title) VALUES ('whatever');
SELECT * FROM files WHERE id = SCOPE_IDENTITY();
Is the safest bet since there is a known issue with OUTPUT Clause conflict on tables with triggers. Makes this quite unreliable as even if your table doesn't currently have any triggers - someone adding one down the line will break your application. Time Bomb sort of behaviour.
See msdn article for deeper explanation:
http://blogs.msdn.com/b/sqlprogrammability/archive/2008/07/11/update-with-output-clause-triggers-and-sqlmoreresults.aspx
Entity Framework performs something similar to gbn's answer:
DECLARE #generated_keys table([Id] uniqueidentifier)
INSERT INTO Customers(FirstName)
OUTPUT inserted.CustomerID INTO #generated_keys
VALUES('bob');
SELECT t.[CustomerID]
FROM #generated_keys AS g
JOIN dbo.Customers AS t
ON g.Id = t.CustomerID
WHERE ##ROWCOUNT > 0
The output results are stored in a temporary table variable, and then selected back to the client. Have to be aware of the gotcha:
inserts can generate more than one row, so the variable can hold more than one row, so you can be returned more than one ID
I have no idea why EF would inner join the ephemeral table back to the real table (under what circumstances would the two not match).
But that's what EF does.
SQL Server 2008 or newer only. If it's 2005 then you're out of luck.
There are many ways to exit after insert
When you insert data into a table, you can use the OUTPUT clause to
return a copy of the data that’s been inserted into the table. The
OUTPUT clause takes two basic forms: OUTPUT and OUTPUT INTO. Use the
OUTPUT form if you want to return the data to the calling application.
Use the OUTPUT INTO form if you want to return the data to a table or
a table variable.
DECLARE #MyTableVar TABLE (id INT,NAME NVARCHAR(50));
INSERT INTO tableName
(
NAME,....
)OUTPUT INSERTED.id,INSERTED.Name INTO #MyTableVar
VALUES
(
'test',...
)
IDENT_CURRENT: It returns the last identity created for a particular table or view in any session.
SELECT IDENT_CURRENT('tableName') AS [IDENT_CURRENT]
SCOPE_IDENTITY: It returns the last identity from a same session and the same scope. A scope is a stored procedure/trigger etc.
SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY];
##IDENTITY: It returns the last identity from the same session.
SELECT ##IDENTITY AS [##IDENTITY];
##IDENTITY Is a system function that returns the last-inserted identity value.
There are multiple ways to get the last inserted ID after insert command.
##IDENTITY : It returns the last Identity value generated on a Connection in current session, regardless of Table and the scope of statement that produced the value
SCOPE_IDENTITY(): It returns the last identity value generated by the insert statement in the current scope in the current connection regardless of the table.
IDENT_CURRENT(‘TABLENAME’) : It returns the last identity value generated on the specified table regardless of Any connection, session or scope. IDENT_CURRENT is not limited by scope and session; it is limited to a specified table.
Now it seems more difficult to decide which one will be exact match for my requirement.
I mostly prefer SCOPE_IDENTITY().
If you use select SCOPE_IDENTITY() along with TableName in insert statement, you will get the exact result as per your expectation.
Source : CodoBee
The best and most sure solution is using SCOPE_IDENTITY().
Just you have to get the scope identity after every insert and save it in a variable because you can call two insert in the same scope.
ident_current and ##identity may be they work but they are not safe scope. You can have issues in a big application
declare #duplicataId int
select #duplicataId = (SELECT SCOPE_IDENTITY())
More detail is here Microsoft docs
You can use scope_identity() to select the ID of the row you just inserted into a variable then just select whatever columns you want from that table where the id = the identity you got from scope_identity()
See here for the MSDN info http://msdn.microsoft.com/en-us/library/ms190315.aspx
Recommend to use SCOPE_IDENTITY() to get the new ID value, But NOT use "OUTPUT Inserted.ID"
If the insert statement throw exception, I except it throw it directly. But "OUTPUT Inserted.ID" will return 0, which maybe not as expected.
This is how I use OUTPUT INSERTED, when inserting to a table that uses ID as identity column in SQL Server:
'myConn is the ADO connection, RS a recordset and ID an integer
Set RS=myConn.Execute("INSERT INTO M2_VOTELIST(PRODUCER_ID,TITLE,TIMEU) OUTPUT INSERTED.ID VALUES ('Gator','Test',GETDATE())")
ID=RS(0)
You can append a select statement to your insert statement.
Integer myInt =
Insert into table1 (FName) values('Fred'); Select Scope_Identity();
This will return a value of the identity when executed scaler.
* Parameter order in the connection string is sometimes important. * The Provider parameter's location can break the recordset cursor after adding a row. We saw this behavior with the SQLOLEDB provider.
After a row is added, the row fields are not available, UNLESS the Provider is specified as the first parameter in the connection string. When the provider is anywhere in the connection string except as the first parameter, the newly inserted row fields are not available. When we moved the the Provider to the first parameter, the row fields magically appeared.
After doing an insert into a table with an identity column, you can reference ##IDENTITY to get the value:
http://msdn.microsoft.com/en-us/library/aa933167%28v=sql.80%29.aspx
How do I retrieve the ID of an inserted row in SQL?
Users Table:
Column | Type
--------|--------------------------------
ID | * Auto-incrementing primary key
Name |
Age |
Query Sample:
insert into users (Name, Age) values ('charuka',12)
In MySQL:
SELECT LAST_INSERT_ID();
In SQL Server:
SELECT SCOPE_IDENTITY();
In Oracle:
SELECT SEQNAME.CURRVAL FROM DUAL;
In PostgreSQL:
SELECT lastval();
(edited: lastval is any, currval requires a named sequence)
Note: lastval() returns the latest sequence value assigned by your session, independently of what is happening in other sessions.
In SQL Server, you can do (in addition to the other solutions already present):
INSERT INTO dbo.Users(Name, Age)
OUTPUT INSERTED.ID AS 'New User ID'
VALUES('charuka', 12)
The OUTPUT clause is very handy when doing inserts, updates, deletes, and you can return any of the columns - not just the auto-incremented ID column.
Read more about the OUTPUT clause in the SQL Server Books Online.
In Oracle and PostgreSQL you can do this:
INSERT INTO some_table (name, age)
VALUES
('charuka', 12)
RETURNING ID
When doing this through JDBC you can also do that in a cross-DBMS manner (without the need for RETURNING) by calling getGeneratedKeys() after running the INSERT
I had the same need and found this answer ..
This creates a record in the company table (comp), it the grabs the auto ID created on the company table and drops that into a Staff table (staff) so the 2 tables can be linked, MANY staff to ONE company. It works on my SQL 2008 DB, should work on SQL 2005 and above.
===========================
CREATE PROCEDURE [dbo].[InsertNewCompanyAndStaffDetails]
#comp_name varchar(55) = 'Big Company',
#comp_regno nchar(8) = '12345678',
#comp_email nvarchar(50) = 'no1#home.com',
#recID INT OUTPUT
-- The '#recID' is used to hold the Company auto generated ID number that we are about to grab
AS
Begin
SET NOCOUNT ON
DECLARE #tableVar TABLE (tempID INT)
-- The line above is used to create a tempory table to hold the auto generated ID number for later use. It has only one field 'tempID' and its type INT is the same as the '#recID'.
INSERT INTO comp(comp_name, comp_regno, comp_email)
OUTPUT inserted.comp_id INTO #tableVar
-- The 'OUTPUT inserted.' line above is used to grab data out of any field in the record it is creating right now. This data we want is the ID autonumber. So make sure it says the correct field name for your table, mine is 'comp_id'. This is then dropped into the tempory table we created earlier.
VALUES (#comp_name, #comp_regno, #comp_email)
SET #recID = (SELECT tempID FROM #tableVar)
-- The line above is used to search the tempory table we created earlier where the ID we need is saved. Since there is only one record in this tempory table, and only one field, it will only select the ID number you need and drop it into '#recID'. '#recID' now has the ID number you want and you can use it how you want like i have used it below.
INSERT INTO staff(Staff_comp_id)
VALUES (#recID)
End
-- So there you go. I was looking for something like this for ages, with this detailed break down, I hope this helps.