0

I'm working on a simple VB NET/WPF application that communicates with a SQL Server 2012 database, which at least two or more people could be using at the same time.

To keep track of any and every change in the database (INSERT/UPDATE/DELETE), I'm implementing a simple trigger-based auditing system, where obviously, any data getting updated/deleted/inserted is saved in its corresponding auditing table, while also keeping track of the user and the date/time of the operation.

I obviously found tons of guides while searching. But I noticed that most of these SQL Server guides would use JOINs in their queries to extract the data stored in the Inserted or Deleted tables, while I achieved the same result without any JOINs.

Exemple :

  • My INSERT trigger :

    CREATE TRIGGER [HumanResources].[after_insert_humanresources_shift]
    ON [HumanResources].[Shift]
    AFTER INSERT
    AS
    BEGIN
    INSERT INTO [HumanResources].[Shift_Audit] 
    (
        -- [EventID], [EventBy] and [EventOn] have autovalues
        [EventType],
        [ShiftID],
        [Name],
        [StartTime],
        [EndTime],
        [ModifiedDate]
    )   
    SELECT 
         'INSERT',
        [ShiftID], 
        [Name], 
        [StartTime], 
        [EndTime], 
        [ModifiedDate]
    FROM 
        [Inserted]
    END
    
  • This guide's INSERT Trigger :

    create trigger tblTriggerAuditRecord on tblOrders
    after 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
    

My DELETE and UPDATE triggers do exactly the same thing. And all these work for both single D/U/I queries or multiple ones (multiple Updates in a single query for instance). Is there a specific reason why I should be using JOINs ?

Naucle
  • 626
  • 12
  • 28

1 Answers1

1

Yes the "inner join inserted i on t.OrderID=i.OrderID" checks for dependencies on orders table, and will insert only records where there are genuine orders in the orders table, inserting to independent tables does not test the data for dependencies at entity level. hope that helps.

jimmy8ball
  • 746
  • 5
  • 15
  • Does this mean that the `Inserted` and `Deleted` tables could already contain data, different than the data being changed by the query that fired the trigger ? – Naucle Apr 18 '17 at 09:23
  • you also need to review how you will deal with multiple updates of the same record and how you will build a history of the updates per user maybe include a position by date updated etc. there are many ways to achieve this audit within CDC (change data capture) using SSIS, I have pasted an example for you to browse through. hope this helps. https://learn.microsoft.com/en-us/sql/integration-services/change-data-capture/change-data-capture-ssis – jimmy8ball Apr 18 '17 at 09:48
  • To my understanding, every DELETE query generates its own independent `Deleted` table which contains the row or rows being deleted by said query, so the trigger knows exactly where to look, without having to JOIN ID's, which was confirmed by tests I did on my trigger. Can you provide an example that would explain your point ? Also, I already tried CDC, the problem is, there is not way to keep track of the user that committed the change. – Naucle Apr 18 '17 at 09:56
  • The deletion event should trigger an insert statement first to the deleted table containing all the rows that are being deleted, followed by a delete statement applied to the orders table. naturally there would need to be a record in the orders table to be deleted and subsequently inserted as a delete event into the audit table – jimmy8ball Apr 18 '17 at 09:57
  • can you not use logging with CDC to capture user based information, i.e. who ran the query at database level. which should cache the user PID? – jimmy8ball Apr 18 '17 at 10:00
  • You unfortunately can't (https://dba.stackexchange.com/questions/34079/change-data-capture-how-to-know-who-made-the-change). Any insert on the CDC tracking table is done automatically by the DB Admin (the SQL Server Agent inserts into the tracking table as the database admin, when the user inserts into the database), so the user always registers as the admin. – Naucle Apr 18 '17 at 10:09
  • Yes you are correct, apologies my mistake, obviously a known issue as stated "by design" CDC would have been my approach, but if the user information is so crucial for you then sticking with triggers is the only way to deal with this. – jimmy8ball Apr 18 '17 at 10:21
  • Having read further into the link you provided above it may be worth noting the workaround for using cdc with user sessions for your solution. – jimmy8ball Apr 18 '17 at 17:51
  • I have already tried that. You basically have to set CDC, plus a trigger on the table to add the user to that table every time there's a U/I/D, so that CDC captures that column too. Using a single trigger instead of CDC + trigger is easier and cleaner IMO. – Naucle Apr 19 '17 at 09:27