SQL Server Create a trigger after update to loop through each updated column

vxqlmq5t  于 2023-05-05  发布在  其他
关注(0)|答案(1)|浏览(132)

I would like to track all changes for specific tables. So I want to have a trigger to fire when table get updated, for each updated field I want to insert a row in my audit log table with the column old value and new value.

For example lets say I have a employee table like this

CREATE TABLE [dbo].[Employee]
(
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [FirstName] [nvarchar](50) NULL,
    [LastName] [nvarchar](50) NULL,
    [Current] [nvarchar](50) NULL,
    [Password] [nvarchar](50) NULL,
    [Active] [bit] NOT NULL
)

And a log table like this

CREATE TABLE [dbo].[Logs]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [TimeStamp] [datetime] NOT NULL,
    [Puser] [nchar](10) NULL,
    [WinUser] [nchar](20) NULL,
    [Computer] [nchar](20) NULL,
    [Type] [nchar](20) NULL,
    [ObjectType] [nchar](20) NULL,
    [ObjectName] [nchar](20) NULL,
    [Action] [nchar](20) NULL,
    [RecordID] [nchar](20) NULL,
    [FIeldName] [nchar](20) NULL,
    [OldValue] [nvarchar](50) NULL,
    [NewValue] [nvarchar](50) NULL,
    [ParentName] [varchar](20) NULL,
    [ParentID] [varchar](20) NULL,
    [RowDump] [nvarchar](max) NULL
)

And I change the password and active column for an employee, I would like to enter 2 rows into the Logs table (including the employee id in recordid, column name in fieldname, oldvalue, newvalue)

Thanks in advance

sg2wtvxw

sg2wtvxw1#

The best method to do this kind of thing is to use existing tools in SQL Server, such as Change Data Capture , and SQL Auditing .

However, if you really want to roll your own logging, the following should get you started.
It's unclear what some of your logging columns are supposed to represent so I've omitted them. It also seems like overkill.

CREATE TRIGGER dbo.LogChanges ON dbo.Employee
FOR INSERT, UPDATE, DELETE
AS

SET NOCOUNT ON;

IF NOT EXISTS (SELECT 1 FROM inserted) AND NOT EXISTS (SELECT 1 FROM deleted)
    RETURN;    -- bail early if no rows
    
INSERT dbo.Logs (
    TimeStamp,
    WinUser,
    Computer,
    Action,
    OldValue,
    NewValue,
    ParentID
)
SELECT
    GETUTCDATE(),
    SUSER_NAME(),
    HOST_NAME(),
    IIF(i.ID IS NOT NULL, IIF(d.ID IS NOT NULL, 'U', 'I'), 'D'),
    v.oldVal,
    v.newVal,
    ISNULL(i.ID, d.ID)
FROM inserted i
FULL JOIN deleted d ON d.ID = i.ID    -- full join on primary key
CROSS APPLY (VALUES
    (i.FirstName, d.FirstName),    -- unpivot all columns
    (i.LastName, d.LastName),
    (i.[Current], d.[Current]),
    (i.Password, d.Password)
) v(newVal, oldVal)
WHERE EXISTS (SELECT v.newVal EXCEPT SELECT v.oldVal);    -- null-aware comparison

If the column types are mixed then you should cast at least the first value in the CROSS APPLY (VALUES to sql_variant .

db<>fiddle

I note that some of your data types are questionable, such as nullable columns, lengths, and object and username columns should be sysname . Plain-text passwords are also a bad idea.

相关问题