天魔窟

勇往直前

Avatar

ASP FAQ # Chinese [1]

http://www.aspfaq.com/show.asp?id=2174

如何获取数据表中最新插入的记录的 ID 编号?

SQL Server 数据库
SQL Server 2000 中提供了若干可以取代 @@IDENTITY 的新函数。这些函数不是全局性的,这比 @@IDENTITY 要好。当插入新记录后,你可以执行:

PRINT IDENT_CURRENT('table')


这行语句将返回最近在名为“table”的表中添加的记录的 ID 编号,不管“table”是否真的被创建。
另一个方法是:

PRINT SCOPE_IDENTITY()


这将返回当前的存储过程,触发器等等所创建的新记录的 ID 编号。

如果你使用的是 SQL Server 的旧版本,那么取得最新 ID 号的最佳办法,是用单独一个存储过程来完成新纪录插入和 ID 的获取。例如:

CREATE PROCEDURE myProc 
    @param1 INT 
AS 
BEGIN 
    SET NOCOUNT ON 
    INSERT INTO someTable 
    ( 
        intField 
    ) 
    VALUES 
    ( 
        @param1 
    ) 
    SET NOCOUNT OFF 
    SELECT NEWID = @@IDENTITY 
END


然后在 ASP 代码中类似这样地调用:

<% 
    fakeValue = 5 
    set conn = Server.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 
%>


如果你使用的是 SQL Server 2000,那么只需将上面存储过程中的

SELECT NEWID = @@IDENTITY

替换为

SELECT NEWID = SCOPE_IDENTITY()

即可。

@@IDENTITY 的全局特性带来的一个问题是,如果你执行了一个 INSERT 操作,而被操作的表有一个响应 INSERT 的触发器,这个触发器又执行了对另一个表的 INSERT 操作(并且在那个表产生了新的记录 ID 号),那么 @@IDENTITY 返回的将是后面产生的这个 ID 号。在 SQL Server 7.0 中,这个问题令人头疼。这里给你一个解决办法,不过,你可能得为此修改大量的代码。

CREATE TRIGGER triggerInsert_tablename ON tablename FOR INSERT AS  
    BEGIN 
        SELECT @@IDENTITY 
        -- rest of trigger's logic... 
    END

Access
新版的 Jet/OLEDB 数据源现在也支持 @@IDENTITY 了,参见 KB #232144(就我的试验,比较麻烦,并且限制很多)

使用 Access 时,要取得最新 ID 你应该会用下面这样的代码:

<% 
    fakeValue = 5 
    set conn = Server.CreateObject("ADODB.Connection") 
    conn.open "<conn string>" 
    conn.execute "Insert into someTable(intField) 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 
%>


这里说“应该”,是因为可能会出现两个几乎同时进行的插入操作,如此便可能返回错误的 ID 号。当然,坦白地讲,对于这种可能出现“同时插入操作”的繁忙应用场景,你应当考虑使用 SQL Server 作为数据库……(ref)然而若要坚持使用 Access 并希望避免上述问题,你可以使用带有类型为 adOpenKeyset 的游标的 Recordset 对象(这是使用 Recordset 代替 SQL 语句的极罕见场景之一)。

<% 
    fakeValue = 5 
    set conn = Server.CreateObject("ADODB.Connection") 
    conn.open "<conn string>" 
    set rs = Server.CreateObject("ADODB.Recordset") 
    rs.open "select [intField] from someTable where 1=0", conn, 1, 3 
    rs.AddNew 
    rs("intField") = fakeValue 
    rs.update 
    response.write "New ID was " & rs("id") 
    rs.close: set rs = nothing 
    conn.close: set conn = nothing 
%>


这里还提供更多信息。

评论已关闭