【问题标题】:Getting an error "Msg 512, Level 16" after insert using a trigger使用触发器插入后出现错误“消息 512,级别 16”
【发布时间】:2021-05-18 15:09:25
【问题描述】:

我需要创建一个触发器,以在每次新增伤害后更新Total 列。

Total 必须随着这种损坏的成本而增加,所以我有这个错误:

消息 512,级别 16,状态 1,过程 TotalDmg,第 4 行
子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。

我的脚本:

create database carsLoan
use carsLoan

create table Loan
(
    idL int primary key, 
    Total float
)

insert into Loan 
values (1, 300), (2, 200), (3, 400)

create table Damage
(
    idD int primary key, 
    idL int references Loan, 
    description varchar(100), 
    Cost float
)

insert into Damage 
values (1, 1, 'Damage1', 70), (2, 2, 'Damage2', 90), (3, 3, 'Damage3', 80)

alter trigger TotalDmg 
on Damage 
after insert 
as
begin
    declare @cost float
    set @cost = (select Cost from Damage 
                 where idD = (select idD from inserted))

    declare @total float
    set @total = (select Total from Loan 
                  where idL = (select idL from inserted))

    update Loan 
    set Total = @total + @cost 
    where idL = (select idL from inserted)
end

【问题讨论】:

  • 你的触发器有缺陷;它假设 INSERT 仅影响 1 行;这根本不是真的。
  • 另外,float 是我认为是货币价值的数据类型的糟糕选择。
  • 您是否记住了每个错误编号?其他人也不会。发布完整的错误消息。
  • @SMor 消息 512,级别 16,状态 1,过程 TotalDmg,第 4 行子查询返回超过 1 个值。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。声明已终止。

标签: sql sql-server database tsql triggers


【解决方案1】:

布伦特奥扎尔说:The Silent Bug I find in Most Triggers:

您没有考虑到inserted 有多行,甚至根本没有。

alter trigger TotalDmg on Damage after insert as
-- the whole batch is the trigger, no need for BEGIN/END

SET NOCOUNT, XACT_ABORT ON;   -- best practice
IF (NOT EXISTS (SELECT 1 FROM inserted))
    RETURN;

update l
set Total = l.Total + i.cost
from Loan l
join (
    select i.idL, sum(i.Cost) cost
    from inserted i
    group by i.idL
) i on i.idL = l.idL;

GO

如果您制作了UPDATE 触发器,请同时将inserteddeleted 表与此代码进行比较:

join (
    select i.idL, sum(i.Cost) cost
    from (
        select i.idL, i.Cost from inserted i
        except
        select d.idL, d.Cost from deleted d
    ) i
    group by i.idL
) i on i.idL = l.idL

另请参阅 my post here 以获取涉及索引视图的更好解决方案

【讨论】:

  • XACT_ABORT 对于触发器自然是启用的——尽管我想再次添加它并没有什么坏处。 “插入多行”或没有! :)
  • @DaleK 另一个错误消息:消息 156,级别 15,状态 1,过程 TotalDmg,第 15 行关键字“on”附近的语法不正确。
  • @Charlieface 出现错误消息:消息 156,级别 15,状态 1,过程 TotalDmg,第 15 行关键字“on”附近的语法不正确。
  • 我个人更喜欢触发器的开始/结束 - 对我来说似乎更清楚;)
  • @Charlieface docs to back up "OFF 是 T-SQL 语句中的默认设置,而 ON 是触发器中的默认设置。"
猜你喜欢
  • 2015-05-22
  • 2022-08-24
  • 1970-01-01
  • 2020-11-11
  • 2021-02-22
  • 1970-01-01
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多