0

我有一个插入语句通过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;
}

为什么会发生这种情况?

4

2 回答 2

4

检查要插入的表是否有任何 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在触发器中拥有或无法控制触发器,则可以使用以下代码解决它。

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

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;
}

这会通过忽略先前关闭的结果集来查找包含您的作用域标识的结果集。

也可以看看:

状态属性nextRecordset()

于 2017-02-22T14:11:13.400 回答
1

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

sp_configure 'disallow results from triggers', 1
GO
RECONFIGURE
GO
于 2017-02-23T12:48:17.967 回答