【问题标题】:Using @@IDENTITY or SCOPE_IDENTITY() + Insert, together in Stored Procedures在存储过程中一起使用 @@IDENTITY 或 SCOPE_IDENTITY() + Insert
【发布时间】:2011-08-30 12:52:43
【问题描述】:

代码是这样的

   INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)

   GetLastInsertID @tablename='TABLE'

GetLastInsertID 是这个存储过程:

   SELECT @@IDENTITY AS LastID FROM TABLE

如何让存储过程按照上面 Select @@IDENTITY 语句中的要求返回“LastID”?

我收到以下错误:

   Incorrect syntax near 'GetLastInsertId'.

...但是当它自己执行时效果很好:

   GetLastInsertID @tablename='TABLE'

好的,谢谢我将它更新为 Scope_Identity()。但是你是说不要把它放在不同的SP中,而是把它和Insert放在同一个SP中?

再次,当我将插入与此组合时,我仍然收到错误:

   SELECT SCOPE_IDENTITY() AS LastID FROM TABLE

这是新的错误信息:

   There is already an object named 'TABLE' in the database.

【问题讨论】:

  • 最好使用SCOPE_IDENTITY() 而不是@@IDENTITY
  • @Joe:见Joel's answer,SCOPE_IDENTITY 不起作用,因为存储过程是不同的范围。
  • 查看Identity Crisis 了解为什么@@IDentity 不好。一篇老文章,但标题好记
  • @Tim - OP 应该放弃为此使用存储过程的想法。它需要在相同的上下文中调用。无论如何,SELECT SCOPE_IDENTITY() 实际上比EXEC GetLastInsertID @tablename='TABLE' 要少输入。

标签: sql-server tsql


【解决方案1】:

将其分离到存储过程中根本不是一个好主意,因为存储过程会创建一个新的范围/上下文。这让你很容易抓住错误的身份证号码。如果会话中的一个用户同时插入多行,您可能会得到错误的结果。

相反,您几乎总是需要 scope_identity() 函数,并且希望在与创建新记录的语句相同的上下文中调用它。

【讨论】:

  • 不确定您的意思“如果会话中的一个用户同时插入多行,您可能会得到错误的结果。”。 AFAIK 唯一的问题是触发器(以及适用于 @@IDENTITYSCOPE_IDENTITY 的并行错误)
  • @Martin - 看到这个msdn page - 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. 所以@@identity 在同一会话中有多个插入时可能会遇到麻烦,即使范围不同。触发器只是最常见的例子。
  • @Martin - 当然。存储过程(即:这个问题);)
  • 是的。我总是会在INSERT 之后立即检查值,所以并没有真正考虑过这种情况!对不起!
【解决方案2】:

首先,您永远不想使用@@identity,因为如果有人添加触发器,它可能会中断。

您要使用的是 OUTPUT 子句或 scope_identity。有关如何使用 OUTPUT 的示例,请参阅联机书籍。

【讨论】:

    【解决方案3】:

    你的错误在于你没有包含EXECUTE 命令,试试这个:

    INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)
    
    EXEC GetLastInsertID @tablename='TABLE'
    

    EXEC 是在您尝试运行没有其他命令的过程时假定的,但是当您包含 INSERT 时,它会要求 EXEC

    现在,您确实需要确定您尝试做的是否是一个好的设计。

    试试这个:

    DECLARE @LastId int
    INSERT INTO TABLE (VAL1,VAL2,VAL3) VALUES (X,Y,Z)
    SELECT @LastID=SCOPE_IDENTITY()
    

    【讨论】:

      【解决方案4】:

      这是我的示例代码。 (但存储过程没有增加任何价值。)

      --First create a test table.
          create table test
          (id int identity,
          name varchar(30))
          go
      
      --A stored proc that returns the scope_identity()  
          create proc dbo.spTest
          as
      
          insert into test(name)
          values ('test')
      
          return scope_identity()
      
          go
      
      
      -- Sample call
          declare @newId int
      
          exec @newId = spTest
      
          print @newId
      

      【讨论】:

      • SP 看起来就是这样,但是在保存/更改 SP 时仍然报错:Msg 2714,数据库中已经有一个名为“spTest”的对象。
      • 混合return 是一个非常糟糕的主意,存储过程不应该使用return(在 SQL 2005 之前可以将其用于错误代码,但现在您可以使用 RAISERROR 并改为 throw )。使用 OUTPUT 参数。
      • 如果您已经有一个名为 spTest 的 sp,您可以将“create proc”更改为“alter proc”。
      • @Remus 这显然是一个简化的例子。
      • @Remus " 存储过程不应该使用 return" 它在哪里说的?
      猜你喜欢
      • 1970-01-01
      • 2011-02-20
      • 2011-01-05
      • 2013-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-11
      • 1970-01-01
      相关资源
      最近更新 更多