【问题标题】:What am I doing wrong with this SQL Server 2012 trigger?这个 SQL Server 2012 触发器我做错了什么?
【发布时间】:2016-06-16 13:27:32
【问题描述】:

我无法让一个简单的触发器起作用。 它在 INSERT 之后触发,测试 A 列是否为空,如果是,则将其设置为同一行上 B 列的值。 插入后,我检查插入的行,B列有值,但A列为空。 触发器已启用并被触发,因为在绝望中我在不同的点将值记录到工作表中, 这些值是预期的。

我什至尝试通过进入此表的设计并为此列指定 1000 的“默认值”来临时绕过此问题,但它仍然为空。 我尝试更改触发器以将 A 列设置为固定值 987,但它仍然为空。

是否有一些我不知道的关于插入的特质?任何建议表示赞赏。

背景 ---------------------------------------------- -------------------------------------------

OPTIONS 是一张存储“选项”的表格,我们的某个活动的参与者可以注册这些“选项”(例如,活动门票、可选的牛排或鸡肉晚餐等) 这些选项会在定义活动时插入(日期、地点、联系信息以及与会者可以注册的选项)。

选项表:

OptionID INT  (Identity, primary key)
...
MaxAttendees INT
...
AvlbRemainingRegQty INT

最后一列是未设置的列 - 它应该是剩余的鸡肉晚餐数量的总和

我以为我疯了和/或做了一些愚蠢的事情,所以我创建了一个 zTestTrigger 表来存储来自 INSERTED 行的值并验证触发器是否到达了某些点。

WhichPartOfTest VARCHAR(100)
OptionID        INT
AvlbRemRegQty   INT
MaxAttendees    INT

--详情 -------------------------------------------- -------

USE [dbname]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER TRIGGER [dbo].[trig_Options_AvlbRemainingRegQty]
ON [dbo].[Options]
AFTER INSERT
AS
SET NOCOUNT ON

DECLARE @I_OptionID INT
DECLARE @I_AvlbRemainingRegQty INT
DECLARE @I_MaxAttendees INT

SELECT
    @I_OptionID            = I.OptionID,
    @I_AvlbRemainingRegQty = ISNULL(I.AvlbRemainingRegQty,-1),
    @I_MaxAttendees        = MaxAttendees
FROM Inserted I

insert into zTestTrigger values ('Start of new test - values from INSERTED row are:',@I_OptionID, @I_AvlbRemainingRegQty, @I_MaxAttendees)

IF ISNULL(@I_AvlbRemainingRegQty,-1) = -1 --(I had also tried checking IF I_AvlbRemainingRegQty IS NULL)

    begin

    insert into zTestTrigger values ('About to update table, setting AvlbRemQty = ' + cast(@I_MaxAttendees as varchar) + ' where id = ' + cast(@I_OptionID as varchar),
@I_OptionID, @I_AvlbRemainingRegQty, @I_MaxAttendees)

    UPDATE Options SET AvlbRemainingRegQty = @I_MaxAttendees WHERE OptionID = @I_OptionID

    --Originally, I tried this:
    --UPDATE OPTIONS SET AvlbRemainingRegQty = ISNULL(MaxAttendees,1000) WHERE OptionID = @I_OptionID
    --This doesn't work either:
    --UPDATE OPTIONS SET SET AvlbRemainingRegQty = SELECT ISNULL(MaxAttendees,1000) FROM Options WHERE OptionID = @I_OptionID) WHERE OptionID = @I_OptionID
    --I even tried:
    --UPDATE OPTIONS SET AvlbRemainingRegQty = 987    WHERE OptionID = @I_OptionID

    declare @error int
    set @error = @@ERROR
    insert into zTestTrigger values ('@@ERROR is ' + cast(@error as varchar), 0,0,0) --Shows that @Error is 0

    end

从zTestTrigger表中选择显示

   "About to update table, setting AvlbRemQty = 1000 where id = 491" , 491, -1, and 1000

我可以选择 ID 为 491 的行,但其 Avlb Rem Qty 为空。

【问题讨论】:

    标签: sql triggers


    【解决方案1】:

    我会个人为此使用instead of 触发器,因为它允许我们从一开始就正确地放入数据。

    但现在,我们将执行后触发器:

    ALTER TRIGGER [dbo].[trig_Options_AvlbRemainingRegQty]
    ON [dbo].[Options]
    AFTER INSERT
    AS
       SET NOCOUNT ON
    
       UPDATE Options
       SET
          AvlbRemainingRegQty = COALESCE(AvlbRemainingRegQty, MaxAttendees)
       WHERE
          OptionID in (select OptionID from inserted)
    

    请注意,this 触发器(与您的触发器不同)识别 inserted 可以包含 0、1 或 多个 行。所以把它当作一个表格,而不是作为一个独立的、标量变量可以分配有意义的值的东西。

    还有一点:

    应该是剩余的鸡肉晚餐数量的总和

    一般来说,这是一个坏主意。如果您分别存储每笔销售的详细信息,则剩余数量是一个可以计算的值。您所做的一切存储这样的值是给自己一个机会,让存储的值与您的其余数据不一致

    【讨论】:

    • 感谢您的建议...但 INSTEAD OF 触发器同样无效。

      asdf
    • Ack,花了 5 分钟回复,所以它丢失了我编辑的评论。您建议的代码显然应该可以工作,但 col 仍未更新。 INSTEAD OF 触发器引发了一个错误,我将在接下来进行研究。我只是有点吃惊——一些非常基本的东西是错误的。顺便说一句,我同意你的第二点,但我为之做这件事的人是我们小商店的资深人士,并不关心数据规范化。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多