为什么SCOPE_IDENTITY()没有返回我插入的ID?

时间:2017-02-22 14:11:13

标签: sql-server last-insert-id scope-identity

我有一个插入语句通过ADODB.Connection.Execute执行插入到具有标识列的MSSQL服务器上的表中,但返回的记录集不返回新插入记录的ID。

我尝试了以下获取记录的插入ID的形式。

INSERT INTO blah VALUES (blah); SELECT SCOPE_IDENTITY()
INSERT INTO blah VALUES (blah); SELECT @@IDENTITY
INSERT INTO blah OUTPUT INSERTED.ID INTO @ID VALUES(blah); SELECT ID FROM @ID

在所有情况下,当查询返回的记录集时,它不包含标识

var I = DB.Execute(insert_statement_from_above);
if (I) {
  var INSERTED_ID = I(0).Value;
}

为什么会发生这种情况?

2 个答案:

答案 0 :(得分:2)

检查所插入的表是否有任何INSERT触发器,并检查那些INSERT触发器是否正在使用SET NOCOUNT ON。

当触发器未指定SET NOCOUNT ON时,如果它更新数据库,它将生成结果集,结果集将出现在包含SCOPE_IDENTITY结果的结果集之前。

请参阅:https://msdn.microsoft.com/en-us/library/ms189837.aspx

实际上发生的事情是记录集包含一个或多个结果集。

TRIGGER RESULT SET
SCOPE_IDENTITY RESULT SET

当您在记录集中查询范围标识时,实际上是在查询触发器的结果集输出。

您可以使用RS.nextRecordset(),然后查询SCOPE_IDENTITY,但如果触发器可能会或可能不会执行更新,您最终不知道哪个结果集包含您的SCOPE_IDENTITY,是不是第一个还是第二个,还有第二个吗?

通常认为触发器指定SET NOCOUNT ON是一种良好做法,但如果您的触发器中必须有SET NOCOUNT OFF或无法控制触发器,则可以使用以下代码解决此问题。

注意:上面示例中的Scope Identity将始终是记录集中的最后一个结果集。所以我们可以找到如下:

var I = DB.Execute(insert_statement_from_above);
if (I) {
  // find the result set with the scope identity in it
  while (I.State == 0) {
    I = I.nextRecordset();
  }
  var INSERTED_ID = I(0).Value;
}

这将通过忽略先前关闭的结果集来查找包含范围标识的结果集。

另见:

State propertynextRecordset()

答案 1 :(得分:0)

如果您可以阻止所有触发器返回结果集,那么服务器选项“禁止从触发器返回结果”可能是您的解决方案。

sp_configure 'disallow results from triggers', 1
GO
RECONFIGURE
GO