Home > Enterprise >  Method to bulk modify triggers in SQL Server database
Method to bulk modify triggers in SQL Server database

Time:10-06

I have a database that uses Insert, Update, and Delete Triggers for almost all tables. They log the host and program performing the operation in a separate auditing table. The triggers all include this select statement to set variables that get inserted into the auditing table:

  select @HostName = HostName, @ProgramName = Program_Name 
    from master..sysprocesses where SPID = @@SPID

We are now looking to migrate to Azure SQL Database, which does not support the master..sysprocesses syntax. It also appears that table is deprecated as well: https://docs.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysprocesses-transact-sql?view=sql-server-ver15

What we need to do is update the triggers to use this instead:

  select @HostName = [host_name], @ProgramName = [program_name]
    from sys.dm_exec_sessions where session_id = @@SPID

However, the database has hundreds of tables and each table has three triggers that need updating. The text-replacement for each trigger is identical. Is there a feasible way to script out something to perform this update on all triggers in the database?

CodePudding user response:

OK, I just tested this by jamming your string in a few triggers (as a comment of course) and then running it. I am not advocating this as the correct way to do it, as this link will help you with the correct way to do dynamic sql https://dba.stackexchange.com/questions/165149/exec-vs-sp-executesql-performance

However, this does work and will help you understand how you would piece these things together to get to that point.

Note, any formatting difference between your triggers may cause this to miss some, so youll want to verify that 0on your own.

DECLARE @string VARCHAR(8000)='select @HostName = HostName, @ProgramName = Program_Name 
from master..sysprocesses where SPID = @@SPID'
, @counter INT=1
, @Max INT
, @Sql VARCHAR(mAX)
;

IF OBJECT_ID('TempDB..#TrigUpdate') IS NOT NULL DROP TABLE #TrigUpdate;

CREATE TABLE #TrigUpdate
    (
        SqlVar VARCHAR(MAX)
        , RowID INT
    )
;

INSERT INTO #TrigUpdate
SELECT REPLACE(REPLACE(t.definition, @string, ''), 'CREATE TRIGGER', 'ALTER TRIGGER')
    , Row_Number() OVER (ORDER BY t.Definition ASC) AS RowID
FROM sys.objects o
INNER JOIN sys.sql_modules t on o.object_id =t.object_id
WHERE o.type_desc='SQL_TRIGGER'
AND CHARINDEX(@string, t.definition,1)>0
;

SET @Max = (SELECT COUNT(*) FROM #TrigUpdate);

WHILE @Counter<=@Max
    BEGIN
        SET @sql = (SELECT SqlVar FROM #TrigUpdate WHERE RowID=@counter);
        EXEC(@Sql);
        SET @Counter=@Counter 1;
    END

CodePudding user response:

It could be done with Object_Definition and Replace.

Create Table #Triggers_new (TriggerName sysname, QueryText VarChar(max))

Declare @string_pattern VarChar(max), @string_replacement VarChar(max) 

Select @string_pattern = '<string_pattern>'
Select @string_replacement = '<string_replacement>'

Insert Into #Triggers_new (TriggerName, QueryText)
Select [name], Replace(Object_Definition(object_id), @string_pattern, @string_replacement)
From sys.objects
Where [type] = 'TR'
Order by [name]

-- Update #Triggers_new Set QueryText = Replace(QueryText, 'Create Trigger ', 'Alter Trigger ')

CodePudding user response:

Why do you use a so heavy query on system table/view that can be changed without your consent ?

Can't you simplify you by using metada functions like :

SELECT HOST_NAME(), PROGRAM_NAME()...

That will give the requested information values ?

  • Related