如何在SQL Server中正确获取触发器文本?

时间:2017-12-23 03:36:58

标签: sql-server database-trigger

假设:

CREATE TABLE X (Id INT)
GO
CREATE TRIGGER Y ON X FOR DELETE AS SET NOCOUNT ON;
GO
sp_rename 'X', 'Z'
GO
SELECT sm.definition v1, OBJECT_DEFINITION(t.object_id) v2, c.text v3
FROM sys.triggers t
JOIN sys.sql_modules sm ON t.object_id = sm.object_id AND t.Name = 'Y'
JOIN sys.syscomments c ON t.object_id = c.id
GO
sp_helptext 'Y'

这个简单的查询创建一个表,在其上放置一个触发器,重命名表并使用四种不同的方式来获取触发器的文本:

  1. sys.sql_modules查看
  2. sys.syscomments查看
  3. OBJECT_DEFINITION功能
  4. sp_helptext功能
  5. 所有这四种方式都会产生触发器的相同文本:

    CREATE TRIGGER Y ON X FOR DELETE AS SET NOCOUNT ON;
    

    当然,这是我的问题,因为此文本不能用于创建触发器 - 表X不再存在。

    现在,如果我在SSMS中选择触发器(当然是在表Z上)并编写CREATE操作脚本,这就是我得到的:

    USE [mydb]
    GO
    
    /****** Object:  Trigger [dbo].[Y]    Script Date: 12/22/2017 10:32:22 PM ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TRIGGER [dbo].[Y] ON [dbo].[Z] FOR DELETE AS SET NOCOUNT ON;
    GO
    
    ALTER TABLE [dbo].[Z] ENABLE TRIGGER [Y]
    GO
    

    这是正确的,与之前的4种方式不同。

    所以,我的问题是 - 如何获得正确的触发器文本?我们可以运行以重新创建触发器。像SSMS一样。

1 个答案:

答案 0 :(得分:2)

SSMS使用SMO进行脚本编写,这会更改CREATE TRIGGER的ON子句以匹配父表的ON子句。您可以使用类似下面示例的SMO PowerShell脚本来获取与SSMS生成的文本相同的文本。只需调整PS脚本即可获得所需的生成选项。

触发文本显然不同步,因为重命名了表而没有重新创建触发器。

try {

    Add-Type -Path "C:\Program Files\Microsoft SQL Server\130\SDK\Assemblies\Microsoft.SqlServer.Smo.dll";

    $sqlServerName = "YourServer";
    $databaseName = "YourDatabase";

    $scriptPath = "c:\temp\Z_TriggerScripts.sql";

    $SMOserver = New-Object Microsoft.SqlServer.Management.Smo.Server($sqlServerName);
    $scriptr = new-object ('Microsoft.SqlServer.Management.Smo.Scripter') ($SMOserver);

    $database = $SMOserver.databases[$databaseName]

    $objectsToScript = @();
    $objectsToScript += $database.Tables["Z"].Triggers;

    $scriptr.Options.FileName = $scriptPath;
    $scriptr.Options.AnsiFile = $false;
    $scriptr.Options.AllowSystemObjects = $false;
    $scriptr.Options.IncludeIfNotExists = $false;
    $scriptr.Options.NoCommandTerminator = $false;
    $scriptr.Options.ScriptBatchTerminator = $true;

    $null = $scriptr.Script($objectsToScript);

}
catch [Exception] {
    $e = $_.Exception
    $e.ToString();
    throw;
}