【问题标题】:How do I get temp values to be set after an insert has occured in a trigger?如何在触发器中发生插入后设置临时值?
【发布时间】:2013-10-30 22:13:36
【问题描述】:

我正在处理一个触发器,当另一个表应用了插入或更新时,它将向表中插入行。到目前为止,Update 部分有效(我最关心的列是 Balance 列),但是当在 Account 表中添加第一行以进行插入时,在我的 AuditTrailCustomerBalance 表中 OldBalance、NewBalance 和 CustNo 设置为 NULL .如何让 NewBalance 和 CustNo 引用刚刚从触发器插入到表中的值?

这里是触发器:

ALTER TRIGGER AuditTrigger
ON Accounts
FOR INSERT, UPDATE
AS      
IF UPDATE( Balance )
BEGIN
    IF EXISTS
    (
        SELECT 'True'
        FROM Inserted i
        JOIN Deleted d
        ON i.AccountID = d.AccountID
    )
    BEGIN           
        --1. Declare temp variables.
        DECLARE @OldBalance NUMERIC( 18, 0 )
        DECLARE @NewBalance NUMERIC( 18, 0 )
        DECLARE @CustNo INT

        --2. Set the variables.
        SELECT @OldBalance = Balance FROM deleted
        SELECT @NewBalance = Balance FROM inserted
        SELECT @CustNo     = CustNo FROM inserted

        INSERT INTO AuditTrailCustomerBalance( TimeChanged, ChangedBy, OldBalance, NewBalance, CustNo )
        VALUES( GETDATE(), SUSER_SNAME(), @OldBalance, @NewBalance, @CustNo )   
    END
END
GO

以及测试语句:

INSERT INTO Custs( CustNo, GivenName, Surname, DOB, SIN )
VALUES( 1, 'Peter', 'Griffen', 'January 15, 1950', '555555555')

INSERT INTO Accounts( CustNo, Type, Balance, AccruedInt, WithdrawalCount )
VALUES( 1, 'Savings', 0, 0, 0 )

UPDATE Accounts SET Balance = 100 
WHERE CustNo = 1

【问题讨论】:

  • 你的触发器坏了。您需要编写访问 inserted 和 deleted 的基于 set 的查询,因为这些表可以包含 多个 行(或没有行),因此分配给标量变量将选择任意值(甚至不一定都来自同一行)。在单个UPDATE 语句中,一些 行的余额可能发生了变化,而其他行可能没有。
  • 好的,我对使用触发器还是新手,所以我应该使用 SET 而不是 SELECT 来分配变量,这就是你的意思?
  • 不,我是说 SELECT @NewBalance = Balance FROM inserted 存在根本缺陷,因为 inserted 可能包含 3 行 - 具有 3 个不同的余额值 - 但显然 @NewBalance 只能设置为等于 其中一个值。

标签: sql sql-server


【解决方案1】:

我相信你想要这样的东西:

ALTER TRIGGER AuditTrigger
ON Accounts
FOR INSERT, UPDATE
AS  
    INSERT INTO AuditTrailCustomerBalance(TimeChanged, ChangedBy,
                                          OldBalance, NewBalance, CustNo )
    SELECT GETDATE(), SUSER_SNAME(),
           COALESCE(d.Balance,0), i.Balance, i.CustNo
    FROM inserted i
            left join
         deleted d
            on
               i.AccountNo = d.AccountNo
    WHERE
        i.Balance <> d.Balance OR
        d.Balance IS NULL

正如我在 cmets 中所说,inserted 和 deleted 可以包含 multiple rows(或不包含行),因此您需要考虑到这一点并编写一个基于集合的查询来处理所有这些行- 还有一些行可能有余额变化,而有些没有 - 所以根据UPDATE(Balance)决定是否写任何条目也是有缺陷的。

【讨论】:

    【解决方案2】:

    如果你确定你的代码可以这样写:

    if (select count(*) from insert) = 1

    并执行您的代码。

    你可以这样插入:

    插入 AuditTrailCustomerBalance (.....) 从插入中选择 ....

    正如已经发布的那样,如果您更新一行或多行(插入相同),则触发器的问题在于调用

    【讨论】:

      猜你喜欢
      • 2013-04-12
      • 1970-01-01
      • 1970-01-01
      • 2011-12-06
      • 1970-01-01
      • 2013-09-29
      • 2016-01-27
      • 2021-03-08
      • 1970-01-01
      相关资源
      最近更新 更多