在 SQL 服务器数据库中批量修改触发器的方法

Method to bulk modify triggers in SQL Server database

我有一个数据库,几乎所有 table 都使用插入、更新和删除触发器。他们在单独的审计 table 中记录执行操作的主机和程序。触发器都包含此 select 语句以设置插入到审计中的变量 table:

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

我们现在正在寻求迁移到不支持 master..sysprocesses 语法的 Azure SQL 数据库。 table 似乎也已弃用:https://docs.microsoft.com/en-us/sql/relational-databases/system-compatibility-views/sys-sysprocesses-transact-sql?view=sql-server-ver15

我们需要做的是更新触发器以改为使用它:

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

但是,数据库有数百个 table,每个 table 都有三个触发器需要更新。每个触发器的文本替换是相同的。有没有一种可行的方法来编写一些脚本来对数据库中的所有触发器执行此更新?

可以用 Object_Definition 和替换来完成。

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 ')

好的,我只是通过在几个触发器中干扰您的字符串(当然作为评论)然后 运行 来测试它。我并不是在提倡这是正确的做法,因为这个 link 将帮助您以正确的方式进行动态 sql https://dba.stackexchange.com/questions/165149/exec-vs-sp-executesql-performance

但是,这确实有效,将帮助您了解如何将这些东西拼凑起来以达到这一点。

请注意,您的触发器之间的任何格式差异都可能导致它遗漏一些,因此您需要自己验证 0。

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

为什么您在系统 table/view 上使用如此繁重的查询,并且可以在未经您同意的情况下进行更改?

你不能使用像 :

这样的 metada 函数来简化你吗
SELECT HOST_NAME(), PROGRAM_NAME()...

这将给出请求的信息值?