using ##identity afer insert - sql

I have an insert sql with sql server and then call select ##identity straight after, i am trying to use the identity id with a stored procedure, is this even possible
eg
insert into ...
select ##identity
EXEc add 'ss' ##identity
thanks
a
edit---
i basically want to use the value of the id which i'm getting now with
SELECT SCOPE_IDENTITY() ;
to use in a query straight after the insert.

Yes, this is possible, though you are probably better off using SCOPE_IDENTITY().
See this SO question about the best way to get the identity of an inserted row.

Answering the (now deleted) question in the comments...
It is possible to use ##IDENTITY directly in the parameter list of the stored procedure call. For SCOPE_IDENTITY() (which you should be using to avoid problems if a trigger is later added to the table) this syntax is not allowed you need to use an intermediate variable as below.
declare #id int
insert into ...
set #id = SCOPE_IDENTITY()
EXEC AddEmp2 0,#id

Related

OUTPUT clause vs. scope_Identity() [duplicate]

I have seen various methods used when retrieving the value of a primary key identity field after insert.
declare #t table (
id int identity primary key,
somecol datetime default getdate()
)
insert into #t
default values
select SCOPE_IDENTITY() --returns 1
select ##IDENTITY --returns 1
Returning a table of identities following insert:
Create Table #Testing (
id int identity,
somedate datetime default getdate()
)
insert into #Testing
output inserted.*
default values
What method is proper or better? Is the OUTPUT method scope-safe?
The second code snippet was borrowed from SQL in the Wild
It depends on what you are trying to do...
##IDENTITY
Returns the last IDENTITY value produced on a connection, regardless of the table that produced the value, and regardless of the scope of the statement that produced the value.
##IDENTITY will return the last identity value entered into a table in your current session. ##IDENTITY is limited to the current session and is not limited to the current scope. For example, if you have a trigger on a table that causes an identity to be created in another table, you will get the identity that was created last, even if it was the trigger that created it.
SCOPE_IDENTITY()
Returns the last IDENTITY value produced on a connection and by a statement in the same scope, regardless of the table that produced the value.
SCOPE_IDENTITY() is similar to ##IDENTITY, but it will also limit the value to your current scope. In other words, it will return the last identity value that you explicitly created, rather than any identity that was created by a trigger or a user defined function.
IDENT_CURRENT()
Returns the last IDENTITY value produced in a table, regardless of the connection and scope of the statement that produced the value. IDENT_CURRENT is limited to a specified table, but not by connection or scope.
Note that there is a bug in scope_identity() and ##identity - see MS Connect: https://web.archive.org/web/20130412223343/https://connect.microsoft.com/SQLServer/feedback/details/328811/scope-identity-sometimes-returns-incorrect-value
A quote (from Microsoft):
I highly recommend using OUTPUT instead of ##IDENTITY in all cases.
It's just the best way there is to read identity and timestamp.
Edited to add: this may be fixed now. Connect is giving me an error, but see:
Scope_Identity() returning incorrect value fixed?
There is almost no reason to use anything besides an OUTPUT clause when trying to get the identity of the row(s) just inserted. The OUTPUT clause is scope and table safe.
Here's a simple example of getting the id after inserting a single row...
DECLARE #Inserted AS TABLE (MyTableId INT);
INSERT [MyTable] (MyTableColOne, MyTableColTwo)
OUTPUT Inserted.MyTableId INTO #Inserted
VALUES ('Val1','Val2')
SELECT MyTableId FROM #Inserted
Detailed docs for OUTPUT clause: http://technet.microsoft.com/en-us/library/ms177564.aspx
-- table structure for example:
CREATE TABLE MyTable (
MyTableId int NOT NULL IDENTITY (1, 1),
MyTableColOne varchar(50) NOT NULL,
MyTableColTwo varchar(50) NOT NULL
)
##Identity is the old school way. Use SCOPE_IDENTITY() in all instances going forward. See MSDN for the repercussions of using ##IDENTITY (they're bad!).
SCOPE_IDENTITY is sufficient for single rows and is recommended except in cases where you need to see the result of an intermediate TRIGGER for some reason (why?).
For multiple rows, OUTPUT/OUTPUT INTO is your new best friend and alternative to re-finding the rows and inserting into another table.
There is another method available in SQL Server 2005 that is outlined in SQL in the Wild.
This will allow you to retrieve multiple identities after insert. Here's the code from the blog post:
Create Table #Testing (
id int identity,
somedate datetime default getdate()
)
insert into #Testing
output inserted.*
default values
A small correction to Godeke's answer:
It's not just triggers you need to worry about. Any kind of nested operation, such as stored procs, that causes identifiers to be created could change the value of ##IDENTITY.
Another vote for scope_identity...
Be carreful while using ##IDENTITY ...
http://dotnetgalactics.wordpress.com/2009/10/28/scope-identity-vs-identity/

How to get the inserted row autoincrement id?

In C# + SQL Server ExecuteScalar() not returning last inserted id I found a nice solution to get the inserted row autoincrement id. So now my query looks just like:
INSERT INTO dbo.YourTable(Col1, Col2, ..., ColN)
OUTPUT Inserted.ID
VALUES(Val1, Val2, ..., ValN);
But unfortunately I am on SQL Server 2000 and this syntax is not available.
What can I use there to achieve the same result?
You can use ##IDENTITY in Sql Server 2000
However you need to be aware of the limitations (which were overcome by SCOPE_IDENTITY). See this article for an explanation http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/
EDIT
MSDN http://msdn.microsoft.com/en-us/library/aa259185%28v=sql.80%29.aspx says that SCOPE_IDENTITY is avaiable in SS2000, so I recomment that you use it instead.
You can get the value by executing SET #<var> = SCOPE_IDENTITY()
This link http://www.mikesdotnetting.com/Article/54/Getting-the-identity-of-the-most-recently-added-record has some more examples of how to use SCOPE_IDENTITY
The answer I have working is to insert rows through a stored procedure, as OUTPUT keyword is not available in ms sql server 2000. Also I had to abandon inserted by the same reason and used scope_identity.
Well, it looks somewhat like this:
CREATE PROCEDURE [dbo].[InsertRow]
#pDate datetime,
#pId int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO nl$RegisterRace ([Date],...)
VALUES (#pDate,...);
SET #pId = scope_identity();
END

Why is ##Identity returning null?

I have a .NET 2010 app hitting a SQL2000 db. The code is pretty basic. When I insert a record, the record is inserted, but the id is not returned. The id column is an int and it is an Idetity. Here is the stored proc...
ALTER PROCEDURE Insert_Vendor
#CorpID as varchar(255),
#TaxpayerID as varchar(255)
AS
Insert into dbo.Vendor
(
vdr_CorpID,
vdr_TaxpayerID
)
values
(
#CorpID,
#TaxpayerID
)
IF ##error <> 0
BEGIN
RETURN -1
END
ELSE
RETURN ##Identity
GO
And on the receiving end...
int myID = (int)(db.ExecuteScalar(dbCommand));
You should always use SCOPE_IDENTITY()
NULL can't be returned via RETURN from a stored proc. You'd get a SQL warning and it would return zero.
ExecuteScalar looks for the 1st row, 1st column of a recordset. There is no recordset above
... So you'd use SELECT SCOPE_IDENTITY() not RETURN SELECT SCOPE_IDENTITY()
ExecuteScalar
executes the query, and returns the
first column of the first row in the
result set returned by the query
So you need to re-write the RETURN statements as
SELECT -1
and (since scope_indentity() returns numeric(38,0))
SELECT CAST(SCOPE_IDENTITY() AS INT)
respectively
you have to call ##IDENTITY right after the insert, use Scope_identity() instead.
Because your question leaves out a lot of details I will just mention a few possible ways around this as it seems impossible to answer a question without all the details. But it's your first time here so you'll get better. You will right?
Anyways first I would say you should always use scope_identity as it is safer. There could be things going on behind the scenes with triggers that could cause this real problems. Stick with scope_identity and you shouldn't have to worry.
Second I would suggest instead of
RETURN
use
SELECT SCOPE_IDENTITY()
Lastly I would say why not just use an OUTPUT parameter vs returning a result. I don't have anything to support this next statement but I would think it is better. Again no proof on that but it just seems like less overhead with output parameter vs resultset that comes with schema.
Just my thoughts.
I personally would recommend using SCOPE_IDENTITY instead of ##IDENTITY. That being said the problem is in the stored procedure. Devio above was correct the execute scalar is looking for the first column of the first row. The RETURN statement will not do this so you will need to use either one of the below items:
IF ##error <> 0
BEGIN
Select -1
END
ELSE
Select ##Identity
or:
IF ##error <> 0
BEGIN
Select -1
END
ELSE
Select SCOPE_IDENTITY()

get new SQL record ID

How can I get back the autogenerated ID for a new record I just inserted?
(Using ASP classic and MSSQL 2005)
SELECT SCOPE_IDENTITY()
using ##IDENTITY can have unexpected results, so be careful how you use that one. Triggers that insert records to other tables will cause the ##IDENTITY value to change - where SCOPE_IDENTITY() will give you the last identity from only your current scope.
Here's a sample that'll show the difference between ##IDENTITY and SCOPE_INSERT() and how they can return different values..
use tempdb
go
create table table1
(ID int identity)
go
create table table2
(ID int identity(100, 1))
go
create trigger temptrig
on table1
for insert
as
begin
insert table2
default values;
end
go
insert table1
default values;
select SCOPE_IDENTITY(),
##IDENTITY
Another option that nobody has discussed here is to use the OUTPUT clause that is in SQL 2005. In this case, you'd just have to add the output clause to your insert, and then catch that recordset from your code. This works well when inserting multiple records instead of just 1...
use tempdb
go
create table table1
(ID int identity)
go
insert table1
output inserted.ID
default values;
--OR...
insert table1
output inserted.$identity
default values;
SELECT ##IDENTITY usually works, but could return the identity of a record inserted because of a trigger or something, and not the original.
SELECT SCOPE_IDENTITY is what I'd recommend. It returns values inserted only within the current scope.
There is also a "IDENT_CURRENT(tablename)" that returns the last identity inserted for a specific table.
There are three ways to get the the last identity in sql.
They were already mentioned by others, but for completeness:
##IDENTITY - can also return ids created in other objects in the same scope (think triggers)
IDENT_CURRENT - limited to a table, but not to your scope, so it can give bad results for busy tables
Scope_Idenity() - Limited to the scope of the request. Use this 99% of the time
Additionally, there are three ways to take that ID and return it to your client code:
Use an output parameter in a stored procedure
INSERT INTO [MyTable] ([col1],[col2],[col3]) VALUES (1,2,3);
SELECT #OutputParameterName = Scope_Identity();
Use a return value.
INSERT INTO [MyTable] ([col1],[col2],[col3]) VALUES (1,2,3);
Return Scope_Identity();
Select the id into a result set. For example, your sql statement would look something like this:
Dim ResultID As Integer
Dim strSQL As String
strSQL = "INSERT INTO [MyTable] ([col1],[col2],[col3]) VALUES (1,2,3); SELECT Scope_Identity();"
rsResults.Open strSQL, oConn
ResultID = rsResults("ID")
Unfortunately (or fortunately, from my point of view) my Classic ASP it too far gone to show examples of the first two from client code.
SELECT ##Identity or SELECT SCOPE_IDENTITY() both work however Selecting SCOPE_Identity() is safer because it returns the last auto generated ID within your current scope. So for example assume we have a table called ScopeIDTable and on this table we have a trigger. This trigger will insert into a record into TriggerIdTable both tables have an auto increment column.
If you use SELECT ##Identity you will get the last auto increment in that session which would be the Id generated from within the trigger (TriggerIdTable).
If you use SELECT SCOPE_IDENTITY() you will get the id from your ScopeIdTable.
You run the query
select scope_identity()
using the same database connection, before doing anything else with it. The result is, as you probably expect, a record set containing a single row that has a single field. You can access the field using index 0, or you can give it a name if you prefer that:
select scope_identity() as lastId
I always wondered why one would ever want to use
##identity
since
select scope_identity()
obviously is the most save way to accomplish what Scot is asking for.
Where multiple records need to inserted at once in a set-based fashion, it can get more interesting.
I have sometimes used GUIDs generated clientside (but for classic ASP you'd probably need to use a utility to generate the values) or, more often, a NEWSQUENTIALID() constraint on the GUID key column at the server end.
I'm aware not everyone like GIUDS though, for some quite valid reasons (their size and how it affects indexing/paging for one).
http://www.sqlmag.com/Articles/Index.cfm?ArticleID=50164&pg=2
Thanks all who suggested SELECT SCOPE_IDENTITY(). I was able to create a stored procedure:
USE [dbname]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[spInsert]
(
#Nn varchar(30)
)
AS
BEGIN TRANSACTION InsertRecord
INSERT INTO A (Nn)
VALUES (#Nn)
SELECT NewID = SCOPE_IDENTITY() -- returns the new record ID of this transaction
COMMIT TRANSACTION InsertRecord
and call the sproc using VB:
Dim strNn '<- var to be passed'
Set cn = Server.CreateObject("ADODB.Connection")
connectString = "DSN"
cn.Open connectString, "user", "PW0rd"
Set rs = Server.CreateObject("ADODB.Recordset")
set rs = cn.Execute("EXEC [dbname].[dbo].[A] #Nn=" & strNn)
'return the value'
resultID = rs(0)
I can now use resultID anytime I refer to the newly created ID.

Reference generated primary key in SQL script

I'm trying to create a bunch of entries in a database with a single script and the problem I'm encountering is how to reference the generated primary key of the previous entry I created.
For example if I created a customer, then tried to create an order for that customer, how do I get the primary key generated for the customer?
I'm using SQLServer.
Like so:
DECLARE #customerid int;
INSERT INTO customers(name) VALUES('Spencer');
SET #customerid = ##IDENTITY;
EDIT:
Apparently it needs to be SCOPE_IDENTITY() in order to function as expected with triggers.
DECLARE #customerid int;
INSERT INTO customers(name) VALUES('Spencer');
SET #customerid = SCOPE_IDENTITY();
If available in your version, use SCOPE_IDENTITY() instead. Safer than ##IDENTITY.
If you are inserting multiple rows at once, you can get all the identities (for use in, say, creating related records) by using the OUTPUT INTO feature of SQL Server 2005 or later.
This could avoid you having to write loops and cursors etc.