Retrieve the PK using ##identity - asp.net

I'm building a website using ASP.NET and SQL Server, and I use
SELECT PK FROM Table WHERE PK = ##identity
My question is which is better and more reliable to retrieve the last inserted PK for multiuser website, using ##identity or using this:
SELECT MAX(PK) FROM Table WHERE PK = Session ("UserID")

I'm not sure exactly what you want to achieve, but the recommended way to retrieve the primary key value of the last statement on a connection is to use SCOPE_IDENTITY()
##Identity is particularly risky where you are using triggers, since it returns the last generated identity value, including those generated by triggers flowing on from a statement.
MSDN has the following to say:
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.
You should certainly use SCOPE_IDENTITY() in favour of the MAX(PK) approach - any number of possible future changes could invalidate this method.

For SQL Server 2005 and above...
You can do the INSERT and SELECT in one call using the OUTPUT clause...
INSERT MyTable (col1, col2, ..., coln)
OUTPUT INSERTED.keycol, INSERTED.col1, INSERTED.col2, ..., INSERTED.coln
VALUES (val1, val2, ..., valn)
Otherwise, you only use SCOPE_IDENTITY()

As mentioned by #David Hall the ##IDENTITY keyword returns the most recently created identity for your current connection, not always the identity for the recently added record in your query and may return an incorrect value. Using MAX(PK) there is a higher chance for an incorrect value and I'd strongly recommend against using it. To avoid the any race conditions I'd suggest that you use SCOPE_IDENTITY() to return the identity of the recently added record in your INSERT SQL Statement or Stored Procedure.

Depends on what you're trying to accomplish. If you want to return the just-generated ID to the ASP.NET code (a typical scenario), then ##identity is your friend. In a high-concurrency situation, mak(PK) is not even guaranteed to be the PK you're after.

Related

How to get the id of a newly-created value with Diesel and SQLite?

Diesel's SqliteBackend does not implement the SupportsReturningClause trait, so the get_result method cannot be used to retrieve a newly created value.
Is there another way to find out the id of the inserted row? Python has a solution for this. The only solution I've found so far is to use a UUID for ids instead of an autoincrement field.
The underlying issue here is that SQLite does not support SQL RETURNING clauses which would allow you to return the auto generated id as part of your insert statement.
As the OP only provided a general question I cannot show examples how to implement that using diesel.
There are several ways to workaround this issue. All of them require that you execute a second query.
Order by id and select just the largest id. That's the most direct solution. It shows directly the issues with doing a second query, as there can be a racing insert at any point in time, so that you can get back the wrong id (at least if you don't use transactions).
Use the last_insert_rowid() SQL function to receive the row id of the last inserted column. If not configured otherwise those row id matches your autoincrement primary integer key. On diesel side you can use no_arg_sql_function!() to define the underlying sql function in your crate.

Database Isolation Models

I have a database with an "ID" column. Whenever there is a new entry for the database, I fetch the last ID from the database, increment the value, and then use it in the Insert statement.
EDIT : I need the ID to use in multiple Insert statements. I will fetch this ID from the primary table and use this ID to insert values into related tables.
NextID = Select Max(ID) + 1 From Table
INSERT INTO Table1(ID, Col1, Col2...) Values(NextId, Value1, Value2...)
INSERT INTO Table2 (ID,col1,col2....) Values (NextID, Value1, Value2...)
I dont know if this is a good way because I know there will be concurrency issues.
When my application tries to read the NextID, there is a chance that another instance of the application is also trying to read the same value and thus concurrency issues may arise.
Is there a proper way to deal with this situation? I mean there are ways to set the database isolation level. Which would be a proper Isolation level for this situation.
Also if anybody could suggest me with an alternate way to maintain and increment manually the ID in the database, I'm also open to that.
If this information is not enough, please let me know what you require.
I am working with ASP.Net with VB and MS Sql Server 2008. I do not want to use the built-in "Identity" of SQL Server.
The only way to get the next ID is to actually insert the row, and use identity. Everything else will fail. So you must start by inserting into the parent table:
begin transaction;
insert into Table (col1, col2, col3) values (value1, value2, value3);
set #Id = scope_identity();
insert into Table1(ID, col1, col2) values (#Id, ...);
insert into Table3(ID, col1, col2) values (#Id, ...);
commit;
This is atomic and concurrency safe.
I do not want to use the built-in "Identity" of SQL Server.
tl;dr. What you 'want' matter little unless you can make a clear justification why. You can do it correctly, or you can spend the time 'ill oblivion reinventing the wheel.
Esentially you have a batch of three SQL statements - one select and two inserts. The database engine can execute another statement from a different session anywhere between them, thus breaking your data consistency - some other session can get the same MAX() value that you've got and use it for other insert statements. The only way to prevent DB engine from doing it is to use transactions. Wrap your batch with BEGIN TRANSACTION ... COMMIT and you are done.
Your way of doing this fine, what you would need is transaction handling..
BEGIN TRANSACTION
begin try
NextID = Select Max(ID) + 1 From Table
INSERT INTO Table1(ID, Col1, Col2...) Values(NextId, Value1, Value2...)
INSERT INTO Table2 (ID,col1,col2....) Values (NextID, Value1, Value2...)
COMMIT TRANSACTION
end try
begin catch
ROLLBACK TRANSACTION
--exception logging goes here
end catch

Select last identity for table in SQLite?

I'm looking for the equivalent of Scope_identity() or ##identity in sql server, except for sqllite?
I'd hate to resort to a max select on the id column, but that is plausible.
Since I have never used SQL Server, I am not exactly sure what ##IDENTITY does, but if I understand this document correctly, then sqlite3_last_insert_rowid() may be what you are looking for.
last_insert_rowid()
This function returns the ROWID of the last row insert from the database connection which invoked the function. The last_insert_rowid() SQL function is a wrapper around the sqlite3_last_insert_rowid() C/C++ interface function.
Reference

asp.net InsertCommand to return latest insert ID

I'm unable to retrieve the latest inserted id from my SQL Server 2000 db using a typed dataset in asp.NET
I have created a tableadapter and I ticked the "Refresh datatable" and "Generate Insert, Update and Delete statements". This auto-generates the Fill and GetData methods, and the Insert, Update, Select and Delete statements.
I have tried every possible solution in this thread
http://forums.asp.net/t/990365.aspx
but I'm still unsuccesfull, it always returns 1(=number of affected rows).
I do not want to create a seperate insert method as the auto-generated insertCommand perfectly suits my needs.
As suggested in the thread above, I have tried to update the InsertCommand SQL syntax to add SELECT SCOPY_IDENTITY() or something similar, I have tried to add a parameter of type ReturnValue, but all I get is the number of affected rows.
Does anyone has a different take on this?
Thanks in advance!
Stijn
I decided to give up, I can't afford to waste any more time on this.
I use the Insert statement after which I do a select MAX(id) query to hget the insert ID
If anyone should have a solution, I'll be glad to read it here
Thanks
Stijn
I successfully found a way to get the incremental id after insert using my table adapter.
My approach is a little different, I'm using a Store procedure to make the insert, so my insert command has all the values but the ID, I made the sp return the ID just calling:
SET #ID=SCOPE_IDENTITY()
and then
COMMIT TRAN
and last line will be
RETURN #ID
Then I searched my table adapter parameters for InsertCommand and set the #RETURNVALUE to the column of the incremental ID of the table, so when it's executed automatically put the return value on the id field.
Hope this help
You need to tell your table's table-adapter to refresh the
data-table after update/insert operation.
This is how you can do that.
Open the properties of TableAdapter -> Default Select Query -> Advnaced options. and Check the option of Refresh the data table. Save the adapter now. Now when you call update on table-adapter, the data-table will be updated [refreshed] after the update/insert operation and will reflect the latest values from database table. if the primary-key or any coloumn is set to auto-increment, the data-table will have those latest value post recent update.
Now you can Call the update as TableAdapterObj.Update(ds.dataTable);
Read latest values from the DataTable(ds.dataTable) coloumns and assign respective values into the child table before update/insert. This will work exactly the way you want.
alt text http://ruchitsurati.net/files/tds1.png

How to Get Last Created Entry's ID From Sql Database With Asp.Net

I will explain problem with an example:
There is two table in my database, named entry, tags
There is a column named ID_ENTRY in both table. When I add a record to table, entry, I have to take the ID_ENTRY of last added record and add it to table, tags. How can I do it?
The only way to do this is with multiple statements. Using dynamic sql you can do this by separating each statement in your query string with a semi-colon:
"DECLARE #ID int;INSERT INTO [Entry] (...) VALUES ...; SELECT #ID = scope_identity();INSERT INTO [TAGS] (ID_ENTRY) VALUES (#ID);"
Make sure you put this in a transaction to protect against concurrency problems and keep it all atomic. You could also break that up into two separate queries to return the new ID value in the middle if you want; just make sure both queries are in the same transaction.
Also: you are using parameterized queries with your dynamic sql, right? If you're not, I'll personally come over there and smack you 10,000 times with a wet noodle until you repent of your insecure ways.
Immediatly after executing the insert statement on first table, you should query ##IDENTITY doing "SELECT ##identity". That will retrieve the last autogenerated ID... and then just insert it on the second table.
If you are using triggers or something that inserts rows... this may be not work. Use Scope_Identity() instead of ##IDENTITY
I would probably do this with an INSERT trigger on the named entry table, if you have all of the data you need to push to the tags table available. If not, then you might want to consider using a stored procedure that creates both inside a transaction.
If you want to do it in code, you'll need to be more specific about how you are managing your data. Are you using DataAdapter, DataTables, LINQ, NHibernate, ...? Essentially, you need to wrap both inserts inside a transaction of some sort so that either inserts get executed or neither do, but the means to doing that depend on what technology you are using to interact with the database.
If you use dynamic sql, why not use Linq to Entity Framework, now EF is the recommend data access technology from Microsoft (see this post Clarifying the message on L2S Futures from ADO.NET team blog), and if you do an insert with EF the last identity id will available for you automatically, I use it all the time it's easy.
Hope this helps!
Ray.

Resources