5

我的应用程序将一些数据插入到表中。

insert into this_Table (id, value, value)

然后,我创建了一个触发器,它使用主键将简单的插入到另一个表中。

insert into temp_wc_triggertest values ('test', GETDATE())

我的问题是,应用程序尝试scope_identity从第一个插入中查找。但是,它会被触发器覆盖,从而将作用域标识更改为temp_wc_triggertest.

如何停止触发器覆盖scope_identity

我意识到这里没有多少代码可以提供帮助,这通常被归类为一个坏问题,但我目前无权访问完整的应用程序代码,所以我希望这是可以回答的。

这是在 SQL Server 2008 R2 上

编辑:我查看了代码,它确实使用了 scope_identity

4

5 回答 5

3

您的客户肯定会使用@@IDENTITY而不是SCOPY_IDENTITY()

这是一个 SQL Fiddle,其中包含一些您可以测试的代码。

SQL小提琴

MS SQL Server 2008 架构设置

create table T1(ID int identity(1,1));
create table T2(ID int identity(1000, 1));

go

create trigger tr_T1 on T1 for insert
as
insert into T2 default values;

查询

insert into T1 default values

select @@identity as "@@identity", 
       scope_identity() as "scope_identity()"

结果

| @@IDENTITY | SCOPE_IDENTITY() |
---------------------------------
|       1000 |                1 |
于 2013-04-08T16:52:48.310 回答
3

如果您正确使用 SCOPE_IDENTIY,您可能还会遇到一个已知错误 - http://connect.microsoft.com/SQLServer/feedback/details/328811

MS 已在 2012 年永久修复它,并为 2008 和 2008R2 提供补丁。

于 2013-04-08T17:03:29.503 回答
2

它覆盖范围标识的原因尚不清楚,可能与提到的错误有关。但是发现了一个修复:

创建了一个临时表“temp_wc”

然后在触发器结束时,为该表打开了标识插入,并为触发器触发后我们想要保留的 ID 完成了插入。这种方法可以被认为是再次覆盖被覆盖的作用域标识。

SET IDENTITY_INSERT ON
INSERT INTO temp_wc VALUES (@ID, 'fix scope identity error')
于 2013-04-30T10:11:16.750 回答
0

这可能会帮助将来解决此问题的任何人:

https://docs.microsoft.com/en-us/sql/t-sql/functions/scope-identity-transact-sql?view=sql-server-2017

您可能需要修补 SQL Server,因为看起来SCOPE_IDENTITY应该返回实际接收主插入的表上的插入 ID,而不是 SQL 触发器插入语句。

来自 SQL Server 2017 的 Microsoft 文档(以防链接损坏):

备注 SCOPE_IDENTITY、IDENT_CURRENT 和@@IDENTITY 是相似的函数,因为它们返回插入标识列的值。

IDENT_CURRENT 不受范围和会话限制;它仅限于指定的表。IDENT_CURRENT 返回为任何会话和任何范围内的特定表生成的值。有关详细信息,请参阅 IDENT_CURRENT (Transact-SQL)。

SCOPE_IDENTITY 和@@IDENTITY 返回在当前会话的任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY 返回仅在当前范围内插入的值;@@IDENTITY 不限于特定范围。

例如,有两个表,T1 和 T2,并且在 T1 上定义了一个 INSERT 触发器。当向 T1 插入一行时,触发器将触发并在 T2 中插入一行。这个场景说明了两个作用域:T1 上的插入和触发器在 T2 上的插入。

假设 T1 和 T2 都有标识列,@@IDENTITY 和 SCOPE_IDENTITY 在 T1 上的 INSERT 语句末尾返回不同的值。@@IDENTITY 返回在当前会话的任何范围内插入的最后一个标识列值。这是插入到 T2 中的值。SCOPE_IDENTITY() 返回插入到 T1 中的 IDENTITY 值。这是在同一范围内发生的最后一个插入。SCOPE_IDENTITY() 函数如果在作用域中出现任何插入标识列的 INSERT 语句之前调用该函数,则返回空值。

失败的语句和事务可能会更改表的当前标识并在标识列值中创建间隙。即使尝试将值插入表的事务未提交,标识值也永远不会回滚。例如,如果 INSERT 语句由于 IGNORE_DUP_KEY 违规而失败,则表的当前标识值仍会递增。

这里的另一个链接:

http://www.sqlbadpractices.com/how-not-to-retrieve-identity-value/

此代码的问题是您可能无法检索您插入的标识值。例如,如果表上有一个触发器在另一个表上执行插入,您将获得最后创建的标识值。即使您从未创建任何触发器,由于 SQL Server 创建自己的复制触发器,您可能会得到复制表的偏差结果。

于 2018-10-15T16:00:21.850 回答
-2

采用SELECT IDENT_CURRENT(‘tablename’)

“它返回表中生成的最后一个 IDENTITY 值,无论创建该值的连接如何,也无论生成该值的语句的范围如何。”

有关详细信息,请参阅此链接。

http://blog.sqlauthority.com/2007/03/25/sql-server-identity-vs-scope_identity-vs-ident_current-retrieve-last-inserted-identity-of-record/

于 2013-04-08T15:39:11.597 回答