为什么 SCOPE_IDENTITY() 不返回我插入的 ID?
Why isn't SCOPE_IDENTITY() returning my inserted ID?
我有一个插入语句通过 ADODB.Connection.Execute
插入到带有标识列的 MSSQL 服务器上的 table 中,但是 returned 记录集没有 return新插入记录的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
在所有情况下,当查询记录集时 returned 它不包含身份
var I = DB.Execute(insert_statement_from_above);
if (I) {
var INSERTED_ID = I(0).Value;
}
为什么会这样?
检查正在插入的 table 是否有任何 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;
}
这将通过忽略之前关闭的结果集来查找包含您的范围标识的结果集。
另请参阅:
如果您可以阻止所有触发器返回结果集,服务器选项 "Disallow returning results from triggers" 可能是适合您的解决方案。
sp_configure 'disallow results from triggers', 1
GO
RECONFIGURE
GO
我有一个插入语句通过 ADODB.Connection.Execute
插入到带有标识列的 MSSQL 服务器上的 table 中,但是 returned 记录集没有 return新插入记录的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
在所有情况下,当查询记录集时 returned 它不包含身份
var I = DB.Execute(insert_statement_from_above);
if (I) {
var INSERTED_ID = I(0).Value;
}
为什么会这样?
检查正在插入的 table 是否有任何 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;
}
这将通过忽略之前关闭的结果集来查找包含您的范围标识的结果集。
另请参阅:
如果您可以阻止所有触发器返回结果集,服务器选项 "Disallow returning results from triggers" 可能是适合您的解决方案。
sp_configure 'disallow results from triggers', 1
GO
RECONFIGURE
GO