【问题标题】:scope_identity returns dbnull due to instead of triggerscope_identity 由于而不是触发器而返回 dbnull
【发布时间】:2012-05-22 18:02:11
【问题描述】:

我在桌子上有一个代替触发器。触发器工作正常,但我们有一个应用程序,用户可以在其中通过 UI 对表执行批量更新。在这种情况下,select scope_identity 返回 null。当用户通过 UI 执行更新时,我运行 sql profiler 来查看后台发生了什么,我得到了这个:

insert into Table(column1, column2,....)
values (value1, value2,.....)
go
select scope_identity()
go

在这种情况下,内部定义的scope_identity()而不是触发器返回正确的值,但上述语句中的scope_identity()返回null,此时应用程序会抛出错误。我想这是因为插入发生在触发器内部,它不属于上述 scope_identity 的范围。 我知道可以通过使用 after trigger 代替 trigger 来解决此问题,但是该表包含 ntext 列,这将阻止我使用 after trigger。将 ntext 列转换为 nvarchar(max) 也不是我的选择。 关于如何使 select scope_identity() 返回正确值的任何想法?

提前致谢。

【问题讨论】:

  • 发布触发器的内容。
  • select scope_identity() 应该与 insert 在同一批次中 - 换句话说,您需要删除 go
  • @Ben:我不能在这里发布触发器,但它是这样的:set ansi_nulls on go setquoted_identifier on go create trigger dbo.sampletrigger on sampletable instead of insert as begin //在此处执行一些操作插入进入 sampletable(column1, column2,..) select column1, column2,... from inserted select scope_identity() end

标签: sql


【解决方案1】:

好的,我可以重现您的问题并给出解释和解决方案。

use tempdb
go
set ansi_nulls on 
set quoted_identifier on 
go 
create table sampletable (
ix int identity primary key,
column1 nvarchar(50),
column2 nvarchar(50)
)
go
go
      /* First with no trigger - works fine */
insert sampletable(column1, column2)
select 'a', 'b'
select @@identity, scope_identity(), ident_current('sampletable')
select * from sampletable

go
      /* create instead trigger */
create trigger dbo.sampletrigger on sampletable 
instead of insert 
as 
begin 
insert into sampletable(column1, column2) select column1, column2 from inserted 
end
go

      /* Now scope_identity() is null */
insert sampletable(column1, column2)
select 'a', 'b'
select @@identity, scope_identity(), ident_current('sampletable')
select * from sampletable
go
go
go
drop table sampletable

Scope_identity() 为 null,因为您没有在当前范围内插入具有标识的行。

Scope_identity() 是当前批次中插入当前作用域的最后一个标识。触发器是一个单独的范围,所以在触发器之外它是空的。 无论范围如何,您都需要使用@@identity,这是插入批次中的最后一个身份。

不能使用ident_current('sampletable'),这是插入到该特定表上的任何批次和任何会话中的最后一个身份,因为这可能会因其他并发用户而获取更改。

【讨论】:

  • 感谢您的回答。我知道如果我使用 @@identity 或 ident_current('sampletable') 它将返回非空值。这里的问题是我原始问题中的以下语句是由应用程序自动生成的,我无权访问后台代码。因此,我无法将 scope_identity() 更改为 @@identity 或 ident_current('')。 insert into Table(column1, column2,....) values (value1, value2,.....) go select scope_identity() go 基本上,我需要一种解决方法,使上述 scope_identity() 返回非空值。不确定这是否可能。
  • @AnutoshDatta,然后您需要找到一种使用AFTER 触发器的方法。由于您还没有告诉我们您实际在做什么,我无法提供更多帮助。
  • 此触发器为表创建更改日志条目。我使用而不是触发器的原因是表有 ntext 列。我无法将其更改为 nvarchar(max),因为它会影响其他区域。无论如何感谢您的帮助。
  • @AnutoshDatta,有一种方法可以解决这个问题,正如我所做的那样。在这里查看我的答案:stackoverflow.com/questions/9101924/…
  • @Ben 我在网上找不到任何地方表明 ident_current 是特定于批次的,它似乎只是返回在给定表上创建的最新 id。说它是特定于批次的似乎意味着范围。在大多数情况下,假设它们是相同的可能是合理的,但在足够的负载下——难道不能保证最新的 ID 和使用给定脚本创建的 ID 相同吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
相关资源
最近更新 更多