Simple trigger for auditing

  • I'm after a simple trigger to audit inserts and deletes on a single table.

    If the PK does not exist in the audit table (i.e. an INSERT has occurred) then insert into the audit table.

    If the PK exists in the audit table (i.e. an UPDATE has occurred) then insert into the audit table the new values if any of the non-key values have changed.

    The table and the audit table will contain the same columns (plus any additional columns required in the audit table).

    I'm struggling to find an example.

    Also, are the data changes made by a trigger included in the transaction, so that they are rolled back if the INSERT or UPDATE on the table are rolled back - I think that is the case?

     

  • Thanks. The first one is simple and a good starting point for me.

    Why in the below is it necessary to join back to tblOrders?

    create trigger tblTriggerAuditRecord on tblOrders
    after update, insert
    as
    begin
    insert into tblOrdersAudit
    (OrderID, OrderApprovalDateTime, OrderStatus, UpdatedBy, UpdatedOn )
    select i.OrderID, i.OrderApprovalDateTime, i.OrderStatus, SUSER_SNAME(), getdate()
    from tblOrders t
    inner join inserted i on t.OrderID=i.OrderID
    end
    go

     

  • It's not. Everything just inserted or updated is in the virtual "inserted" table, so the join adds no value.

    Good observation.

  • That join is not needed.

    are the data changes made by a trigger included in the transaction, so that they are rolled back if the INSERT or UPDATE on the table are rolled back?

    Yes, the trigger is part of the transaction and will be rolled back if the trans fails.

    If the PK exists in the audit table (i.e. an UPDATE has occurred) then insert into the audit table the new values if any of the non-key values have changed.

    Do you want to log columns only if the value changes?  Or just log every column every time?

    SQL DBA,SQL Server MVP(07, 08, 09) A socialist is someone who will give you the shirt off *someone else's* back.

  • Good, I couldn't understand why the join was there.

    Scott - I would want to log all columns, but only if one or more of the values have changed. An UPDATE that happened to not change any column values would not go into the audit.

     

  • SET ANSI_NULLS ON;
    SET QUOTED_IDENTIFIER ON;
    GO
    CREATE TRIGGER tblTriggerAuditRecord
    ON dbo.tblOrders
    AFTER INSERT, UPDATE
    AS
    SET NOCOUNT ON;
    INSERT INTO dbo.tblOrdersAudit
    ( OrderID, OrderApprovalDateTime, OrderStatus, /*...,*/ UpdatedBy, UpdatedOn )
    SELECT i.OrderID, i.OrderApprovalDateTime, i.OrderStatus, /*...,*/ SUSER_SNAME(), GETDATE()
    FROM dbo.tblOrders t
    INNER JOIN deleted d ON d.OrderID=t.OrderID
    WHERE
    (d.OrderApprovalDateTime IS NULL OR t.OrderApprovalDateTime <> d.OrderApprovalDateTime) OR
    (t.OrderStatus <> d.OrderStatus) /*OR ...*/
    /*end of trigger*/
    GO

    SQL DBA,SQL Server MVP(07, 08, 09) A socialist is someone who will give you the shirt off *someone else's* back.

  • Thanks.

    FROM dbo.tblOrders t

    INNER JOIN deleted d ON d.OrderID=t.OrderID

    I was thinking it was:

    FROM dbo.tblOrders t

    LEFT JOIN deleted d ON d.OrderID=t.OrderID

    or

    FROM inserted i

    LEFT JOIN deleted d ON i.OrderID=d.OrderID

     

  • Oops, quite true, since I did a combined trigger.

    I suggest separating the INSERT and UPDATE triggers.  Then you can use INNER JOIN and not have to test for INSERT vs UPDATE in the trigger.

    ...

    AFTER UPDATE

    ...

    For the INSERT trigger, you don't need to join to anything, since all the columns are known to be "changed", i.e. new.

    SQL DBA,SQL Server MVP(07, 08, 09) A socialist is someone who will give you the shirt off *someone else's* back.

Viewing 9 posts - 1 through 8 (of 8 total)

You must be logged in to reply to this topic. Login to reply