Identifying New Records

While the use of AutoNumber and Identity fields in tables is greatly applauded by database designers the world over, they can be annoying for developers to use. The problem being that, when we add records to the database, there are many cases where we need to know the key of the record that has just been added. Fortunately, there are a number of techniques that are available to assist us in our task. In this article we look at the methods for both SQL Server and Access, with an eye to the pros and cons of each approach. As always, our goal is to give you enough information to make up your own mind

SQL Server

SQL Server 2000 offers three, count 'em, three options for retrieving the Id of a recently added record. The 'best' method depends on what you're doing and what else might be going on in your database. In all cases, the Id is a field marked as the primary key of a table and that has the Identity property set to True.

@@IDENTITY This is an intrinsic variable in SQL Server that contains the Id of the record that was last created on this connection, regardless of the table.
IDENT_CURRENT('table') This function returns the ID of the record that was last created in the specified table.
SCOPE_IDENTITY This variable contains the Id of the last record that was created within the current scope, regardless of the table.

So what are the ramifications of using each of these options? With @@IDENTITY, you get the most recent identity on the current connection. That means that if, as part of the INSERT statement, triggers get executed that in turn INSERT records into other tables, @@IDENTITY contains the last Id that was generated. Regardless of the table into which the record was inserted. Now if you created all of the stored procedures, triggers and INSERT statements yourself, that is fine. You can control when the @@IDENTITY value is being checked. But what happens if, sometime in the future, another developer, who is unaware that @@IDENTITY is being used, adds a trigger that creates an Audit log record. All of a sudden, @@IDENTITY returns a different id.  And not the one for the just added record.  As a result, your application breaks even though 'nothing' has changed. And that is the kind of bug that we all just love to track down.

The IDENT_CURRENT function is best used when you can control who has access to the database and when. By specifying the table as part of the function, you can eliminate the issues associated with @@IDENTITY. At least as far as the addition of records in triggers goes,   However IDENT_CURRENT works at the table level, not the connection level.  It returns the most recently created id, regardless of who created it. Unfortunately, in a busy environment, developers can't be sure between the execution of the INSERT command and the retrieval of IDENT_CURRENT, a different record isn't inserted by another user.

The SCOPE_IDENTITY instrinsic variable addresses some of the issues raised with the other two methods. Its value is the last Id created within the current scope. Athough technically the scope is the current connection, practically, the scope is more typically the currently executing stored procedure. Now you don't have to worry about the possibility of future enhancements 'breaking' your code, nor do you have to deal with other activity impacting the Id that is returned. If you perform more that one INSERT in a stored procedure, you do need to use the SCOPE_IDENTITY between each statement in order to retreive all of the created Id's. But again, that is within your sphere of control.

Unfortunately, if you are using SQL Server 7.0 or earlier, then the @@IDENTITY method is the only choice available to you. Both IDENT_CURRENT and SCOPE_IDENTITY were introduced with SQL Server 2000.

Microsoft Access

With Access, you are limited to basically a single technique. On a positive note, the same technique works all the way back to Access 97

First of all, I assume that we are inserting a record into a table where the primary key has an AutoNumber type. The addition of the record must be accomplished by using the AddNew and Update methods of the ADO Recordset object. Then, once the record has been added, store the absolute position of the new record and perform a Requery. Finally, set the cursor back to the bookmarked record and read the Id. Seem like a lot of work? And inflexible to boot? Such is the joy of Access

Set cn = CreateObject("ADODB.Connection")
Set rs = CreateObject("ADODB.Recordset")

cn.Open "DSN=MyDSN;"

rs.CursorLocation = adUseClient
rs.Open "SELECT CustNo, CustomerName, Contact", cn, adOpenStatic, adLockOptimistic

rs.AddNew

' CustNo is the AutoNumber field
rs.Fields("CustomerName").Value = "ObjectSharp"
rs.Fields("Contact").Value = "Bruce Johnson"
rs.Update

' The record has been inserted, but rs.Fields("CustNo").Value is zero
bookmark = rs.absolutePosition
rs.Requery
rs.absolutePosition = bookmark

' Voila
MsgBox rs.Fields("CustNo").Value

Comments

  • bruce December 1, 2003 10:48 AM

    Thanks for the explanation. How about some examples of useage?

  • bruce March 5, 2004 6:41 PM

    Thanks for the tip. Here are two for you:
    1. If the table is an ACCESS table; using DAO; the key is available between the .AddNew and the .Update:
    .AddNew
    saveKey = rs.Fields("CustNo").Value
    .Update

    2. Using your tip; with ADO 2.7; The key is NOT available between .AddNew and .Update, but IS avalailable after the .Update without need for the .Requery:
    .AddNew
    .Update
    saveKey = rs.Fields("CustNo").Value

  • bruce December 17, 2004 11:42 AM

    I know this is an old thread, but I found it while looking for MS Access info. Trying to convert a MySQL db to Access. Just wanted to point out MySQL has a function to do this for you.
    http://dev.mysql.com/doc/mysql/en/Getting_unique_ID.html

  • bruce February 20, 2005 8:18 PM

    none

  • bruce August 17, 2005 3:50 PM

    Using Access 2003/Sql Server 2000, I do the following:
    sql = "Insert..."
    cnn.execute sql

    sql = "select @@identity"
    Set rs = cnn.Execute(sql, , adCmdText)

    If Not rs.EOF Then
    lngNewObjectID = rs.Fields(0)
    End if

  • bruce September 24, 2005 8:51 AM

    i use asp+sqlserver but today i was trying to create a shoping cart in access and getting the problem , i did search from google and got solution from ur site. so i thing that i must say thnx to you.

    thnx
    Aziz A. Khan

  • bruce November 20, 2005 6:29 AM

    asdasd

  • bruce November 20, 2005 6:36 AM

    I tried a lot to figure out an equivalent of @@IDENTITY in case of Oracle. But unfortunate;lly there is no one step method. Its basically a workaround. Instead of Specifying Sequence_Name.NEXTVAL inside the Insert Statement, store the value of the same in a separate variable before executing the Actual Insert Statement and then pass this variables value in the Insert Statement. This way the value will be saved.
    Doing the same after the execution of the Insert Statement using Sequence_Name.CURRVAL is not recommended due to the inconsistencies that may arise in case of a concurrent access scenario.

    mailto:saikat_tota@rediffmail.com

  • bruce May 1, 2006 7:46 AM

    I just read the article and replies and was wondering how can we get the id of the new record in Access using ADO.Net? Can anyone provide a solution.

    Regards
    Umer

  • bruce July 14, 2006 6:44 PM

    the @@IDENTITY method does work with later versions of access as it is part of Microsoft Jet 4.0 . However Ive encountered errors when using it with autonumbers greater than 32,000

    http://support.microsoft.com/kb/232144/EN-US/

  • bruce July 16, 2006 10:29 AM

    hi,
    Really, a very informative article. Is that means there is no substantial way to get the last record ID. I am talking about MS SQL Server. How do other people with good number of traffic on their server get the problem solved? Is there is no way to escape from this ambiguity

    Aakash

  • bruce December 12, 2006 12:59 AM

    hi,
    I understand the concept but i would like to get(select) last n records which are inserted to a table.is it possible to get like tht?

  • Mitch May 15, 2008 9:23 AM

    Is it possible to get the Id of the record before it is inserted?  

    i.e. When you open a table with an autonumber field(customerid) and type something in another field(customername) the autonumber populates.  Now if I press esc the insert cancels. No record was inserted.  I need to know how to do this with code.

    thanks

  • rocarobin August 15, 2008 1:59 PM

    Note:

    SCOPE_IDENTITY

    IDENT_CURRENT('table')

    @@IDENTITY

    LAST_INSERT_ID()

    Can only be use, IF! the id was built-in Auto-Incrementing.

    I hope this helps.

  • Parveen Sharma September 12, 2008 5:38 AM

    i m finding

    id value of last record insterted

    and doesn't find the id value

    id no is primary and autoincrement field

    but doesn't access id ref just help and find soluation

    parveensharma.pta@gmail.com

Leave a Comment

(required) 
(optional)
(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS