假设:
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'
这个简单的查询创建一个表,在其上放置一个触发器,重命名表并使用四种不同的方式来获取触发器的文本:
sys.sql_modules
查看sys.syscomments
查看OBJECT_DEFINITION
功能sp_helptext
功能所有这四种方式都会产生触发器的相同文本:
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一样。
答案 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;
}