触发器更新引发的异常'无法为更新行集定位:一些值可能已在最后读取后改变', 该怎么修改触发器

98049522 2004-12-24 03:47:16
有两个表, 报价单, 订单表, 报价单有一个bit字段<是否接单>记录本报价单是否接到订单;订单表中有一个字段<对应报价单号>记录本订单对应报价单号.
在删除订单时需要修改对应报价单的是否接单字段.
在订单表中定义如下触发器:
CREATE TRIGGER tg_订单_Del ON [dbo].[订单]
for DELETE
AS
update 报价表
set 是否接单=0
where 报价单号=
(select 对应报价单号
from deleted)
GO
在订单有报价单对应时运行正常.
但当订单没有对应的报价单时(直接下的订单,或对应报价单已经被删除). 将出现'无法为更新行集定位:一些值可能已在最后读取后改变'的异常, 我是使用事务进行更新的.

在问专家上看到的回答是:
由于所修改的记录与数据库所存在的记录冲突,导致更改失败(如其他用户已将记录删除),如果没有触发器,其实程序发生警告信息给Errors集合,但不终止程序运行,也不会出实时错误提示。如果你加上触发器,你所进行批更新包括从Deleted表中记录,即所有删除的记录,所有的更新请求都不存在(或已被其它用户删除),所以出现实时运行错误。

对于我的情况, select 对应报价单号 from deleted 将是NULL值, 但这并不影响Update语句的执行啊??

请高手解疑!
...全文
378 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
98049522 2004-12-27
  • 打赏
  • 举报
回复
使用这样的方法解决了:
CREATE TRIGGER tg_订单_Del ON [dbo].[订单]
for DELETE
AS
--if exists (select 对应报价单号 from deleted)
--begin
select 对应报价单号 from deleted
--select '存在'
update 报价表
set 是否接单=0
where 报价单号=
(select 对应报价单号
from deleted)
--end


98049522 2004-12-25
  • 打赏
  • 举报
回复
lipkissnow(雨水,我在傘中央) 的方法应该是类似的了
98049522 2004-12-25
  • 打赏
  • 举报
回复
按照 vinsonshen(猪骨褒咸鱼->味道没得顶) 使用的语句:
CREATE TRIGGER tg_订单_Del ON [dbo].[订单]
for DELETE
AS
if exists (select * from deleted)
update 报价表
set 是否接单=0
where 报价单号=
(select 对应报价单号
from deleted)
GO
使用照样出错, 但是如果在if内加上一个select语句便可以了
if exists (select * from deleted)
select '执行到这'
update 报价表
set 是否接单=0
where 报价单号=
(select 对应报价单号
from deleted)
猜想:MSSQL事务检测触发器是否成功执行是根据判断返回值的, 如果没有对应的报价单,那么触发器内的update语句的影响行是0, 而有对应的报价单, 触发器内的update影响行是1. 这就导致了有对应报价单时删除可以成功执行,没有时事务会回滚.
另外 这条语句if exists (select * from deleted) 总是为真的.
把它改为:if exists (select 对应报价单号 from deleted) ,而订单中这个字段为空,但语句结果还是为真, 不知道是为什么?
lipkissnow 2004-12-24
  • 打赏
  • 举报
回复
update 报价表 set 是否接单=0 where 报价单号= (select 对应报价单号 from deleted)
就樓主的這條語句來講后面用等號與(select 对应报价单号 from deleted)相連就不委.因為后面查到的一個集合.改成update 报价表 set 是否接单=0 where 报价单号 in (select 对应报价单号 from deleted)好些,當然對一條記錄可以.如果是多條記錄就會產生數據混亂.
至於為什麼會產生樓主所說的問題.樓主為什麼不走另一條路呢.
你有說過訂單有對應報價單時不會錯.那麼我定義一個 變量取得當前訂單的報價單號.不就行了嗎.如下:
CREATE TRIGGER tg_订单_Del ON [dbo].[订单]
for DELETE
AS
declare @報價單號 int

select @報價單號=報價單號 from deleted
if @報價單號 is not null or @報價單號<>'' --條件根據樓主自行定義

update 报价表 set 是否接单=0 where 报价单号= (select 对应报价单号 from deleted)
GO

--上面只是針對單條記錄.如果是多條記錄同時進行.最好還是用游標.

--以上意見僅供參考
qiliu 2004-12-24
  • 打赏
  • 举报
回复
但是确实存在,如果同时操作因为不存在产生的这个无法定位的情况。
其他的还不知道;
qiliu 2004-12-24
  • 打赏
  • 举报
回复
由于所修改的记录与数据库所存在的记录冲突,导致更改失败(如其他用户已将记录删除),如果没有触发器,其实程序发生警告信息给Errors集合,但不终止程序运行,也不会出实时错误提示。如果你加上触发器,你所进行批更新包括从Deleted表中记录,即所有删除的记录,所有的更新请求都不存在(或已被其它用户删除),所以出现实时运行错误。

不知道为什么?
98049522 2004-12-24
  • 打赏
  • 举报
回复
这个我当然知道:
update a set a.是否接单=0 from 报价表 a, deleted b where a.报价单号=b.对应报价单号

在我的应用中使用触发器更好
Liroyal 2004-12-24
  • 打赏
  • 举报
回复
update a set a.是否接单=0 from 报价表 a, deleted b where a.报价单号=b.对应报价单号
vinsonshen 2004-12-24
  • 打赏
  • 举报
回复
改成这样试试:
CREATE TRIGGER tg_订单_Del ON [dbo].[订单]
for DELETE
AS
if exists (select * from deleted)
update 报价表
set 是否接单=0
where 报价单号=
(select 对应报价单号
from deleted)
GO
chd2001 2004-12-24
  • 打赏
  • 举报
回复
跟其他字段有关把。

27,579

社区成员

发帖
与我相关
我的任务
社区描述
MS-SQL Server 应用实例
社区管理员
  • 应用实例社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧