【问题标题】:Trigger is not fired for all rows in case of update(random)在更新(随机)的情况下,不会为所有行触发触发器
【发布时间】:2019-09-11 06:14:27
【问题描述】:

我创建了一个触发器来捕获副本表中的所有插入、更新和删除操作,但在更新的情况下,插入两行,其中一个具有更新前的值,另一行具有更新后的值,但它不能作为预计。

我已经尝试了所有可能的方法来做到这一点。现在,我想知道是否应该在触发级别使用事务进行更新操作,还是应该尝试其他方法。

ALTER TRIGGER [dbo].[trgAfterInsertUpdateDelete_xyz] ON [dbo].[xyz] 
FOR UPDATE,INSERT, DELETE
AS
declare @accountID int;
declare @billingDate date;
declare @amount decimal(18, 2);

---- Get data from inserted/ updated
select @accountID = i.AccountID from inserted i;    
select @billingDate=i.BillingDate from inserted i;  
select @amount=i.Amount from inserted i;

-- Insert Case
IF EXISTS( SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted) 
BEGIN
    insert into xyz_Audit
    (AccountID, BillingDate, Amount, Audit_Action) 
    values(@accountID,@billingDate,@amount,'INSERT');
END

-- Update Case
IF EXISTS( SELECT * FROM inserted) AND EXISTS(SELECT * FROM deleted)
BEGIN
    INSERT INTO xyz_Audit
    (AccountID, BillingDate, Amount, Audit_Action)
    SELECT d.AccountID, d.BillingDate, d.Amount,             
            'BeforeUpdate'  FROM Inserted i
    INNER JOIN Deleted d ON i.ID = d.ID

    INSERT INTO xyz_Audit
    (AccountID, BillingDate, Amount,Audit_Action) 

         values(@accountID,@billingDate,@amount,'AfterUpdate');
END


-- Delete Case
IF EXISTS( SELECT * FROM deleted) AND NOT EXISTS(SELECT * FROM inserted)
BEGIN
    INSERT INTO xyz_Audit
    (AccountID, BillingDate, Amount, Audit_Action) 
    select accountID,billingDate,amount, 'DELETE'
    from deleted
END

我预计如果更新了 9 条记录,那么所有行的更新值之前和之后应该都有,但有时它会跳过。正如您在 Inst.8 中看到的那样,应该有行之前和之后,但它只捕获了行之前然后插入,但实际上没有删除和插入行,只完成了更新。在 9 个中的某个时候,它只在行之前而不是在更新行之后选择,或者有时在更新行之后而不是在更新行之前选择 2 或 3 个。

【问题讨论】:

    标签: sql-server tsql database-trigger


    【解决方案1】:

    您的触发器假设插入/更新/删除操作只会影响一行。这意味着inserteddeleted 可能包含多行

    以下部分不处理。

    ---- Get data from inserted/ updated
    select @accountID = i.AccountID from inserted i;    
    select @billingDate=i.BillingDate from inserted i;  
    select @amount=i.Amount from inserted i;
    

    实际上,您根本不需要上述内容。您应该直接从inserteddeleted 表中插入Audit

    例如"INSERT CASE" 应该是

    -- Insert Case
    IF EXISTS( SELECT * FROM inserted) AND NOT EXISTS(SELECT * FROM deleted) 
    BEGIN
        insert into xyz_Audit (AccountID, BillingDate, Amount, Audit_Action) 
        select AccountID, BillingDate, Amount, Audit_Action= 'INSERT'
        from   inserted;
    END
    

    同样,您需要对“更新”部分进行相应更改。并且您已经为删除部分正确地做到了

    【讨论】:

    • 好的,谢谢您的回复。你 100% 确定这是唯一的问题。现在,每当有 9 或 18 行进行更新时,它都会捕获所有行的前后行。因为有时它以适当的方式工作,有时不是@squirrel
    • 还有一件事,触发器的第二个更新部分是否需要事务?它会按顺序或随机方式插入数据吗?意思是 Inst。 1 同时或以某种随机方式具有前后行
    • 它将按照您的插入语句的顺序进行
    • 谢谢@squirrel 如果在尝试一段时间后数据捕获没有发生错误,肯定会接受它作为答案。非常感谢你
    猜你喜欢
    • 2013-09-29
    • 1970-01-01
    • 1970-01-01
    • 2016-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多