sql-servert-sqltriggers

Trigger AFTER INSERT, UPDATE, DELETE to call stored procedure with table name and primary key


For a sync process, my SQL Server database should record a list items that have changed - table name and primary key.

The DB already has a table and stored procedure to do this:

EXEC @ErrCode = dbo.SyncQueueItem "tableName", 1234;

I'd like to add triggers to a table to call this stored procedure on INSERT, UPDATE, DELETE. How do I get the key? What's the simplest thing that could possibly work?

CREATE TABLE new_employees
(
    id_num INT IDENTITY(1,1),
    fname VARCHAR(20),
    minit CHAR(1),
    lname VARCHAR(30)
);
GO

IF OBJECT_ID ('dbo.sync_new_employees','TR') IS NOT NULL 
    DROP TRIGGER sync_new_employees;
GO

CREATE TRIGGER sync_new_employees
ON new_employees
AFTER INSERT, UPDATE, DELETE
AS
     DECLARE @Key Int;
     DECLARE @ErrCode Int;

     --  How to get the key???
     SELECT @Key = 12345; 

     EXEC @ErrCode = dbo.SyncQueueItem "new_employees", @key;
GO

Solution

  • Not the best solution, but just a direct answer on the question:

    SELECT @Key = COALESCE(deleted.id_num,inserted.id_num);
    

    Also not the best way (if not the worst) (do not try this at home), but at least it will help with multiple values:

    DECLARE @Key INT;
    DECLARE triggerCursor CURSOR LOCAL FAST_FORWARD READ_ONLY 
        FOR SELECT COALESCE(i.id_num,d.id_num) AS [id_num]
            FROM inserted i
            FULL JOIN deleted d ON d.id_num = i.id_num
            WHERE (
                    COALESCE(i.fname,'')<>COALESCE(d.fname,'')
                 OR COALESCE(i.minit,'')<>COALESCE(d.minit,'')
                 OR COALESCE(i.lname,'')<>COALESCE(d.lname,'')
            )
    ;
    
    OPEN triggerCursor;
    FETCH NEXT FROM triggerCursor INTO @Key;
    WHILE @@FETCH_STATUS = 0
    BEGIN
        EXEC @ErrCode = dbo.SyncQueueItem 'new_employees', @key;
        FETCH NEXT FROM triggerCursor INTO @Key;
    END
    
    CLOSE triggerCursor;
    DEALLOCATE triggerCursor;
    

    Better way to use trigger based "value-change-tracker":

    INSERT INTO [YourTableHistoryName] (id_num, fname, minit, lname, WhenHappened)
    SELECT COALESCE(i.id_num,d.id_num) AS [id_num]
        ,i.fname,i.minit,i.lname,CURRENT_TIMESTAMP AS [WhenHeppened]
    FROM inserted i
    FULL JOIN deleted d ON d.id_num = i.id_num
    WHERE ( COALESCE(i.fname,'')<>COALESCE(d.fname,'')
        OR COALESCE(i.minit,'')<>COALESCE(d.minit,'')
        OR COALESCE(i.lname,'')<>COALESCE(d.lname,'')
    )
    ;
    

    The best (in my opinion) way to track changes is to use Temporal tables (SQL Server 2016+)