Trigger for Update action without primary key

  • Hi,

    I am writing a trigger for getting values to auditlog table when the values gets updated. Below is the code of my trigger.

    CREATE TRIGGER [dbo].[Update_Temp] ON [dbo].[Temptable1] FOR UPDATE

    AS

    DECLARE @bit INT ,

    @field INT ,

    @maxfield INT ,

    @char INT ,

    @fieldname VARCHAR(128) ,

    @TableName VARCHAR(128) ,

    @PKCols VARCHAR(1000) ,

    @sql VARCHAR(2000),

    @UpdateDate VARCHAR(21) ,

    @UserName VARCHAR(128) ,

    @Type CHAR(1) ,

    @PKSelect VARCHAR(1000),

    @HostName varchar(100),

    @AppName varchar(100)

    --You will need to change @TableName to match the table to be audited.

    SELECT @TableName = 'Temptable1'

    -- date and user

    SELECT @UserName = SYSTEM_USER ,

    @UpdateDate = CONVERT(VARCHAR(8), GETDATE(), 112)

    + ' ' + CONVERT(VARCHAR(12), GETDATE(), 114)

    SELECT

    @HostName= CASE WHEN LEN(HOST_NAME()) < 1 THEN '<Unidentified> ' ELSE HOST_NAME() END

    SELECT

    @AppName= CASE WHEN LEN(APP_NAME()) < 1 THEN '<Unidentified> ' ELSE APP_NAME() END

    -- Action

    IF EXISTS (SELECT * FROM inserted)

    IF EXISTS (SELECT * FROM deleted)

    SELECT @Type = 'U'

    ELSE

    SELECT @Type = 'I'

    ELSE

    SELECT @Type = 'D'

    -- get list of columns

    SELECT * INTO #ins FROM inserted

    SELECT * INTO #del FROM deleted

    -- Get primary key columns for full outer join

    SELECT @PKCols = COALESCE(@PKCols + ' and', ' on')

    + ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME

    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,

    INFORMATION_SCHEMA.KEY_COLUMN_USAGE c

    WHERE pk.TABLE_NAME = @TableName

    AND CONSTRAINT_TYPE = 'PRIMARY KEY'

    AND c.TABLE_NAME = pk.TABLE_NAME

    AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

    -- Get primary key select for insert

    SELECT @PKSelect = COALESCE(@PKSelect+'+','')

    + '''<' + COLUMN_NAME

    + '=''+convert(varchar(100),

    coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>'''

    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,

    INFORMATION_SCHEMA.KEY_COLUMN_USAGE c

    WHERE pk.TABLE_NAME = @TableName

    AND CONSTRAINT_TYPE = 'PRIMARY KEY'

    AND c.TABLE_NAME = pk.TABLE_NAME

    AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME

    IF @PKCols IS NULL

    BEGIN

    RAISERROR('no PK on table %s', 16, -1, @TableName)

    RETURN

    END

    SELECT @field = 0,

    @maxfield = MAX(ORDINAL_POSITION)

    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = @TableName

    WHILE @field < @maxfield

    BEGIN

    SELECT @field = MIN(ORDINAL_POSITION)

    FROM INFORMATION_SCHEMA.COLUMNS

    WHERE TABLE_NAME = @TableName

    AND ORDINAL_POSITION > @field

    SELECT @bit = (@field - 1 )% 8 + 1

    SELECT @bit = POWER(2,@bit - 1)

    SELECT @char = ((@field - 1) / 8) + 1

    IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0 OR @Type IN ('I','D')

    BEGIN

    SELECT @fieldname = COLUMN_NAME

    FROM INFORMATION_SCHEMA.COLUMNS

    WHERE TABLE_NAME = @TableName

    AND ORDINAL_POSITION = @field

    SELECT @sql = '

    insert Audit ( Type,

    TableName,

    PK,

    FieldName,

    OldValue,

    NewValue,

    UpdateDate,

    UserName)

    select ''' + @Type + ''','''

    + @TableName + ''',' + @PKSelect

    + ',''' + @fieldname + ''''

    + ',convert(varchar(1000),d.' + @fieldname + ')'

    + ',convert(varchar(1000),i.' + @fieldname + ')'

    + ',''' + @UpdateDate + ''''

    + ',''' + @UserName + ''''

    + ' from #ins i full outer join #del d'

    + @PKCols

    + ' where i.' + @fieldname + ' <> d.' + @fieldname

    + ' or (i.' + @fieldname + ' is null and d.'

    + @fieldname

    + ' is not null)'

    + ' or (i.' + @fieldname + ' is not null and d.'

    + @fieldname

    + ' is null)'

    EXEC (@sql)

    END

    END

    The code is working fine when the table has primary key associated. However due to some restrictions I will not be able to have a primary key for some tables. I want to implement the same trigger in those tables too. When there is primary key, that primary key needs to get inserted into the audit table and if there is no primary key, i want a specific column value to get inserted instead of the primary key value into the audit table.

    For example, i have a student table in which there is a student id, name, dob. there is no primary key defined for the table. So when i update the name or dob, i need the student id to get inserted into the Pk column of the audit table.

    I tried modifying the code by checking the @pkcols for Null and if its null to get the old value as the primary key however I was not able to do it .

  • That trigger is way too much overhead. The trigger itself cannot be dynamic. Instead, dynamic code should be used to generate a static trigger, which will need regenerated only when the identifying key column(s) on a table change, whether they are PKs or not.

    SQL DBA,SQL Server MVP(07, 08, 09) "It's a dog-eat-dog world, and I'm wearing Milk-Bone underwear." "Norm", on "Cheers". Also from "Cheers", from "Carla": "You need to know 3 things about Tortelli men: Tortelli men draw women like flies; Tortelli men treat women like flies; Tortelli men's brains are in their flies".

Viewing 2 posts - 1 through 1 (of 1 total)

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