Huy Phong - moingaymotniemvui.com-huyphong.com
trang chủ | ảnh | phonghtn@gmail.com
How do I get the IDENTITY / AUTONUMBER
Internet1/14/2006

SQL Server
    With SQL Server 2000, there are a couple of new functions that are better than @@IDENTITY. Both of these functions are not global to the connection, which is an important weak point of @@IDENTITY. After doing an insert, you can call: 
     
    PRINT IDENT_CURRENT('table') 
     
    This will give the most recent IDENTITY value for 'table' - regardless of whether you created it or not (this overrides the connection limitation of @@IDENTITY -- which can be useful). 
     
    Another thing you can do is: 
     
    PRINT SCOPE_IDENTITY() 
     
    This will give the IDENTITY value last created within the current stored procedure, trigger, etc.  
     
    If you using a version of SQL Server prior to 2000 (or you are in compatibility mode < 80), the best way is to use a single stored procedure that handles both the INSERT and the IDENTITY retrieval using @@IDENTITY. 
     
    Here is sample code for the stored procedure: 
     
    CREATE PROCEDURE myProc 
        @param1 INT 
    AS 
    BEGIN 
        SET NOCOUNT ON 
        INSERT INTO someTable 
        ( 
            intColumn 
        ) 
        VALUES 
        ( 
            @param1 
        ) 
        SELECT NEWID = SCOPE_IDENTITY() 
    END
     
    And you would call this from ASP as follows: 
     
    <% 
        fakeValue = 5 
        set conn = CreateObject("ADODB.Connection") 
        conn.open "<conn string>" 
        set rs = conn.execute("EXEC myProc @param1=" & fakeValue) 
        response.write "New ID was " & rs(0) 
        rs.close: set rs = nothing 
        conn.close: set conn = nothing 
    %>
     
    If you are using SQL Server 7.0, simply change the line in the stored procedure from ... 
     
    SELECT NEWID = SCOPE_IDENTITY()
     
    ... to ... 
     
    SELECT NEWID = @@IDENTITY
     
    The reason SCOPE_IDENTITY() is preferred over @@IDENTITY is that if you perform an INSERT, and that table has an INSERT TRIGGER which then, in turn, inserts into another table with an IDENTITY column, @@IDENTITY is populated with the second table's IDENTITY value. So, if you are stuck using SQL Server 7.0 and need a workaround to retrieving the @@IDENTITY value because you have a trigger that also inserts into another IDENTITY-bound table, you're in luck. You can add this code to the first line of the trigger, but you will have to update all of your application and stored procedure code to deal with this new SELECT: 
     
    CREATE TRIGGER triggerInsert_tablename ON tablename FOR INSERT AS  
    BEGIN 
        SELECT @@IDENTITY 
        -- rest of trigger's logic... 
    END 
    GO
     
    With that said, there are also potential cases where SCOPE_IDENTITY() can fail, but I think this possibility is more remote than with @@IDENTITY. Observe this repro, provided by David Portas: 
     
    CREATE TABLE Table1 

        i INTEGER IDENTITY(1,1) PRIMARY KEY, 
        x INTEGER NOT NULL UNIQUE 

    GO 
     
    CREATE TRIGGER trg_Table1 ON Table1 
    INSTEAD OF INSERT 
    AS 
    BEGIN 
        SET NOCOUNT ON 
        INSERT INTO Table1 (x) 
        SELECT x FROM Inserted 
    END 
    GO 
     
    INSERT INTO Table1 (x) VALUES (1) 
    GO 
     
    SELECT SCOPE_IDENTITY(), IDENT_CURRENT('Table1')
     
    Result: 
     
    ------ ------ 
    NULL   1
     
    This is because the actual INSERT happened outside of the scope of the caller, so SCOPE_IDENTITY() was not populated there. I have requested that the documentation for SCOPE_IDENTITY() be updated to reflect the above scenario.
Access
    Jet/OLEDB provider now supports @@IDENTITY! See KB #232144 for more info, and see Article #2126 to ensure you are using a Jet/OLEDB connection string. 
     
    So with that new information, here is the technique for obtaining this value using Access: 
     
    <% 
        fakeValue = 5 
        set conn = CreateObject("ADODB.Connection") 
        conn.open "<conn string>" 
        sql = "INSERT someTable(IntColumn) values(" & fakeValue & ")" & _ 
            VBCrLf & " SELECT @@IDENTITY" 
        set rs = conn.execute(sql) 
        response.write "New ID was " & rs(0) 
        rs.close: set rs = nothing 
        conn.close: set conn = nothing 
    %>
     
    If you are unable to use JET 4.0, you can do a more risky hack like this: 
     
    <% 
        fakeValue = 5 
        set conn = CreateObject("ADODB.Connection") 
        conn.open "<conn string>" 
        conn.execute "INSERT someTable(IntColumn) values(" & fakeValue & ")" 
        set rs = conn.execute("select MAX(ID) from someTable") 
        response.write "New ID was " & rs(0) 
        rs.close: set rs = nothing 
        conn.close: set conn = nothing 
    %>
     
    This is more risky because it is remotely possible for two people to "cross" inserts, and receive the wrong autonumber value back. To be frank, if there is a possibility of two or more people simultaneously adding records, you should already be considering SQL Server (see Article #2182). However, if you're stuck with Access and need more security that this won't happen, you can use a Recordset object with an adOpenKeyset cursor (this is one of those rare scenarios where a Recordset object actually makes more sense than a direct T-SQL statement): 
     
    <% 
        fakeValue = 5 
        set conn = CreateObject("ADODB.Connection") 
        conn.open "<conn string>" 
        set rs = CreateObject("ADODB.Recordset") 
        rs.open "SELECT [intColumn] from someTable where 1=0", conn, 1, 3 
        rs.AddNew 
        rs("intColumn") = fakeValue 
        rs.update 
        response.write "New ID was " & rs("id") 
        rs.close: set rs = nothing 
        conn.close: set conn = nothing 
    %>
     

Internet
 

Mail to: phonghtn@gmail.com
Danh sách bài viết
  • SQL stored procedures that return an incremented number - Huy Phong(1/14/2006)
  • GetRandomRecord - Huy Phong(1/14/2006)
  • Bài viết
    Bài của Huy Phong (1/14/2006)

    SQL stored procedures that return an incremented number

    SQL stored procedures that return an incremented number

    Often you need to add an item to a table and return the id (autonumber) value of the new entry.

    You can use SQL Server's identity column feature for the underlying structure:

    CREATE TABLE [AutoResponses]
    ([id] [int] IDENTITY (1, 1) NOT NULL,
    [Responding PF] [varchar] (50) NOT NULL,
    [Sender email] [varchar] (100) NOT NULL,
    [Sender name] [varchar] (100) NOT NULL,
    [Subject] [varchar] (100) NULL,
    [Entry date] [smalldatetime] NOT NULL)
    ON [PRIMARY]
    GO
    CREATE CLUSTERED INDEX [IX_AutoResponses] ON [AutoResponses]([Responding PF], [Sender name]) ON [PRIMARY]
    GO
    ALTER TABLE [AutoResponses] WITH NOCHECK
    ADD CONSTRAINT [DF_AutoResponses_Entry date] DEFAULT (getdate()) FOR [Entry date],
    CONSTRAINT [PK_AutoResponses] PRIMARY KEY NONCLUSTERED ([id])
    ON [PRIMARY]
    GO

    You could now use an ordinary insert statement and each new record would have a new [identitycol] property; you could then retrieve that value using the @@identity global variable created by SQL server:

    INSERT INTO [AutoResponses]
    ([Responding PF]
    , [Sender email]
    , [Sender name]
    , Subject)
    VALUES
    ("a","b","c","d")

    Notice the id field is incremented automatically and the [Entry Date] field is automatically set by the default getdate()

    Select @@identity

    There are two problems here:

    • without a transaction around the statement, the @@identity you retrieve may not be the last record of the insert statement you have just executed (although you can get around this in SQL2000 with the SCOPE_IDENTITY or IDENT_CURRENT properties)
    • You have had to go to SQL Server twice

    This is where a stored procedure is needed that both sets the new data and retrieves the @@identity value.

    CREATE Procedure NewResponse
     @pf varchar(50)
     ,@email varchar(100)
     ,@name varchar(100)
     ,@subj varchar(100)
     ,@autonum int OUTPUT
    AS
     begin tran
     insert AutoResponses
     ([Responding PF], [Sender email], [Sender name], Subject)
     values
     (@pf,@email, @name, @subj)
     set @autonum = @@identity
     commit tran
    GO

    Using VB code to insert the new data and retrieve the new id value can now be done in one move, using the Data Environment (DE) or the connection object:

    Private Function GetTrackingNum() As Long
     Dim resp As Long
     DE.NewResponse m_RequestingPF, m_Senderemail, m_SenderName, m_Subject, resp
     GetTrackingNum = resp
    End Function

    By encapsulating this process into a stored procedure and a class function call, you can create a VB class for a DLL that accepts 4 parameters corresponding to the input parameters of the SQL Stored procedures and returns one value -- the new id.

    Public Property Get TrackingNumber() As Long
       TrackingNumber = GetTrackingNum()
    End Property

    Public Property Let Senderemail(ByVal vData As String)
      m_Senderemail = vData
    End Property

    Public Property Let SenderName(ByVal vData As String)
      m_SenderName = vData
    End Property

    Public Property Let RequestingPF(ByVal vData As String)
      m_RequestingPF = vData
    End Property

    Public Property Let Subject(ByVal vData As String)
      m_Subject = Trim(vData)
    End Property

    You can register this DLL on Exchange Server and then have a script call it every time a new message arrives in a Public Folder

     
    Bài của Huy Phong (1/14/2006)

    GetRandomRecord
    CREATE PROCEDURE sp_GetRandomRecord
    AS
    
    declare @nRecordCount int
    declare @nRandNum int
    
    -- Create a temporary table with the same structure of
    -- the table we want to select a random record from
    CREATE TABLE #TempTable
    (
      field1 varchar(255),
      field2 varchar(50),
      field3 int,
      idNum int identity(1,1)
    )
    
    -- Dump the contents of the table to seach into the 
    -- temp. table
    INSERT INTO #TempTable
    Select field1, field2, field3 From myTable
    
    -- Get the number of records in our temp table
    Select @nRecordCount = count(*) From #TempTable
    
    -- Select a random number between 1 and the number
    -- of records in our table
    Select @nRandNum = Round(((@nRecordCount - 2) * Rand() + 1), 0)
    
    -- Select the record from the temp table with the
    -- ID equal to the random number selected...
    Select field1, field2, field3 From #TempTable
    Where idNum = @nRandNum
    Go
    
     
  • Những bài cũ hơn
  • Tìm kiếm với hàm instr trong ASP (12/7/2005)
  • Đổi owner của các bảng trong SQLServer (12/14/2005)
  • How to Use Windows XP: Setting Up a Network Printer (12/20/2005)
  • Install Network Printer on Windows XP (12/20/2005)
  • Password Generator (1/5/2006)
  • Checking valid email function (1/9/2006)
  • Những bài mới hơn
  • Sử dụng Subquery trong Store Procedure (1/16/2006)
  • Many-to-many selections query (1/17/2006)
  • Để không mất email trong outlook khi cài đặt lại máy (5/3/2006)
  • How to decrease the Size of the Transaction Log in SQL Server 2000 (6/19/2006)
  • Download Source Code HPBlog (8/6/2006)
  • IIS 7 (12/5/2006)
  • Vista (12/6/2006)
  • Tìm kiếm:    Tìm
    Chủ đề khác:
    blog comments powered by Disqus