我想生成一个包含SQL的SQL脚本,以创建我们数据库中存在的所有触发器。触发器是通过SSMS查询窗格直接添加的,因此,除了数据库本身的触发器之外,当前没有其他源。
我已经尝试过右键单击数据库的方法,选择Tasks->Generate Scripts
并使用"脚本整个数据库和所有对象"选项。虽然这确实为表和约束创建了一个SQL脚本,但它不会为触发器生成SQL。
我也理解我可以右键单击数据库中的每个触发器并选择Generate SQL Script选项,但是当前有46个表在审计中(For Insert,Update和Delete)。
而是为46个表中的每个表手动生成插入,更新和删除触发器脚本,是否有更简单的方法来执行此操作?或者,我应该开始点击,复制和粘贴吗?
答案 0 :(得分:77)
<强>数据库 - &GT;任务 - &GT;生成脚本 - &gt;下一步 - &gt;下一步
在选择脚本选项 UI上,在表格/视图选项标题下,将脚本触发设置为True 。
答案 1 :(得分:45)
我知道答案已被接受,但是想要提供另一种解决方案,因为某些原因SSMS向导无法为触发器生成脚本(在我的情况下是MSSQL2008R2)
此解决方案基于上述dana的想法,但如果超过4000个字符('syscomments'视图的'text'列的限制),则使用'sql_modules'来提供触发器的完整代码< / p>
select [definition],'GO' from sys.sql_modules m
inner join sys.objects obj on obj.object_id=m.object_id
where obj.type ='TR'
右键单击结果网格,然后将“将结果另存为...”保存到保留格式的文件
答案 2 :(得分:7)
这个怎么样?
select text from syscomments where text like '%CREATE TRIGGER%'
编辑 - 根据下面的jj评论,syscomments
已弃用,将来会被移除。请使用上面列出的基于向导或基于脚本的解决方案:)
答案 3 :(得分:2)
要编写所有触发器的脚本,您可以定义存储过程:
SET ANSI_NULLS ON;
GO
SET QUOTED_IDENTIFIER ON;
GO
-- Procedure:
-- [dbo].[SYS_ScriptAllTriggers]
--
-- Parameter:
-- @ScriptMode bit
-- possible values:
-- 0 - Script ALTER only
-- 1 - Script CREATE only
-- 2 - Script DROP + CREATE
ALTER PROCEDURE [dbo].[SYS_ScriptAllTriggers]
@ScriptMode int = 0
AS
BEGIN
DECLARE @script TABLE (script varchar(max), id int identity (1,1))
DECLARE
@SQL VARCHAR(8000),
@Text NVARCHAR(4000),
@BlankSpaceAdded INT,
@BasePos INT,
@CurrentPos INT,
@TextLength INT,
@LineId INT,
@MaxID INT,
@AddOnLen INT,
@LFCR INT,
@DefinedLength INT,
@SyscomText NVARCHAR(4000),
@Line NVARCHAR(1000),
@UserName SYSNAME,
@ObjID INT,
@OldTrigID INT;
SET NOCOUNT ON;
SET @DefinedLength = 1000;
SET @BlankSpaceAdded = 0;
SET @ScriptMode = ISNULL(@ScriptMode, 0);
-- This Part Validated the Input parameters
DECLARE @Triggers TABLE (username SYSNAME NOT NULL, trigname SYSNAME NOT NULL, objid INT NOT NULL);
DECLARE @TrigText TABLE (objid INT NOT NULL, lineid INT NOT NULL, linetext NVARCHAR(1000) NULL);
INSERT INTO
@Triggers (username, trigname, objid)
SELECT DISTINCT
OBJECT_SCHEMA_NAME(B.id), B.name, B.id
FROM
dbo.sysobjects B, dbo.syscomments C
WHERE
B.type = 'TR' AND B.id = C.id AND C.encrypted = 0;
IF EXISTS(SELECT C.* FROM syscomments C, sysobjects O WHERE O.id = C.id AND O.type = 'TR' AND C.encrypted = 1)
BEGIN
insert into @script select '/*';
insert into @script select 'The following encrypted triggers were found';
insert into @script select 'The procedure could not write the script for it';
insert into
@script
SELECT DISTINCT
'[' + OBJECT_SCHEMA_NAME(B.id) + '].[' + B.name + ']' --, B.id
FROM
dbo.sysobjects B, dbo.syscomments C
WHERE
B.type = 'TR' AND B.id = C.id AND C.encrypted = 1;
insert into @script select '*/';
END;
DECLARE ms_crs_syscom CURSOR LOCAL forward_only FOR
SELECT
T.objid, C.text
FROM
@Triggers T, dbo.syscomments C
WHERE
T.objid = C.id
ORDER BY T.objid,
C.colid
FOR READ ONLY;
SELECT @LFCR = 2;
SELECT @LineId = 1;
OPEN ms_crs_syscom;
SET @OldTrigID = -1;
FETCH NEXT FROM ms_crs_syscom INTO @ObjID, @SyscomText;
WHILE @@fetch_status = 0
BEGIN
SELECT @BasePos = 1;
SELECT @CurrentPos = 1;
SELECT @TextLength = LEN(@SyscomText);
IF @ObjID <> @OldTrigID
BEGIN
SET @LineID = 1;
SET @OldTrigID = @ObjID;
END;
WHILE @CurrentPos != 0
BEGIN
--Looking for end of line followed by carriage return
SELECT @CurrentPos = CHARINDEX(CHAR(13) + CHAR(10), @SyscomText, @BasePos);
--If carriage return found
IF @CurrentPos != 0
BEGIN
WHILE ( ISNULL(LEN(@Line), 0) + @BlankSpaceAdded + @CurrentPos - @BasePos + @LFCR ) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength - (ISNULL(LEN(@Line), 0) + @BlankSpaceAdded );
INSERT
@TrigText
VALUES
( @ObjID, @LineId, ISNULL(@Line, N'') + ISNULL(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''));
SELECT
@Line = NULL,
@LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen,
@BlankSpaceAdded = 0;
END;
SELECT @Line = ISNULL(@Line, N'') + ISNULL(SUBSTRING(@SyscomText, @BasePos, @CurrentPos - @BasePos + @LFCR), N'');
SELECT @BasePos = @CurrentPos + 2;
INSERT
@TrigText
VALUES
( @ObjID, @LineId, @Line );
SELECT @LineId = @LineId + 1;
SELECT @Line = NULL;
END;
ELSE
--else carriage return not found
BEGIN
IF @BasePos <= @TextLength
BEGIN
/*If new value for @Lines length will be > then the
**defined length
*/
WHILE ( ISNULL(LEN(@Line), 0) + @BlankSpaceAdded + @TextLength - @BasePos + 1 ) > @DefinedLength
BEGIN
SELECT @AddOnLen = @DefinedLength - ( ISNULL(LEN(@Line), 0 ) + @BlankSpaceAdded );
INSERT
@TrigText
VALUES
( @ObjID, @LineId, ISNULL(@Line, N'') + ISNULL(SUBSTRING(@SyscomText, @BasePos, @AddOnLen), N''));
SELECT
@Line = NULL,
@LineId = @LineId + 1,
@BasePos = @BasePos + @AddOnLen,
@BlankSpaceAdded = 0;
END;
SELECT @Line = ISNULL(@Line, N'') + ISNULL(SUBSTRING(@SyscomText, @BasePos, @TextLength - @BasePos+1 ), N'');
IF LEN(@Line) < @DefinedLength AND CHARINDEX(' ', @SyscomText, @TextLength + 1) > 0
BEGIN
SELECT
@Line = @Line + ' ',
@BlankSpaceAdded = 1;
END;
END;
END;
END;
FETCH NEXT FROM ms_crs_syscom INTO @ObjID, @SyscomText;
END;
IF @Line IS NOT NULL
INSERT
@TrigText
VALUES
( @ObjID, @LineId, @Line );
CLOSE ms_crs_syscom;
insert into @script select '-- You should run this result under dbo if your triggers belong to multiple users';
insert into @script select '';
IF @ScriptMode = 2
BEGIN
insert into @script select '-- Dropping the Triggers';
insert into @script select '';
insert into @script
SELECT
'IF EXISTS(SELECT * FROM sysobjects WHERE id = OBJECT_ID(''[' + username + '].[' + trigname + ']'')'
+ ' AND ObjectProperty(OBJECT_ID(''[' + username + '].[' + trigname + ']''), ''ISTRIGGER'') = 1)'
+ ' DROP TRIGGER [' + username + '].[' + trigname +']' + CHAR(13) + CHAR(10)
+ 'GO' + CHAR(13) + CHAR(10)
FROM
@Triggers;
END;
IF @ScriptMode = 0
BEGIN
update
@TrigText
set
linetext = replace(linetext, 'CREATE TRIGGER', 'ALTER TRIGGER')
WHERE
upper(left(replace(ltrim(linetext), char(9), ''), 14)) = 'CREATE TRIGGER'
END
insert into @script select '----------------------------------------------';
insert into @script select '-- Creation of Triggers';
insert into @script select '';
insert into @script select '';
DECLARE ms_users CURSOR LOCAL forward_only FOR
SELECT
T.username,
T.objid,
MAX(D.lineid)
FROM
@Triggers T,
@TrigText D
WHERE
T.objid = D.objid
GROUP BY
T.username,
T.objid
FOR READ ONLY;
OPEN ms_users;
FETCH NEXT FROM ms_users INTO @UserName, @ObjID, @MaxID;
WHILE @@fetch_status = 0
BEGIN
insert into @script select 'setuser N''' + @UserName + '''' + CHAR(13) + CHAR(10);
insert into @script
SELECT
'-- Text of the Trigger' =
CASE lineid
WHEN 1 THEN 'GO' + CHAR(13) + CHAR(10) + linetext
WHEN @MaxID THEN linetext + 'GO'
ELSE linetext
END
FROM
@TrigText
WHERE
objid = @ObjID
ORDER
BY lineid;
insert into @script select 'setuser';
FETCH NEXT FROM ms_users INTO @UserName, @ObjID, @MaxID;
END;
CLOSE ms_users;
insert into @script select 'GO';
insert into @script select '------End ------';
DEALLOCATE ms_crs_syscom;
DEALLOCATE ms_users;
select script from @script order by id
END
如何执行:
SET nocount ON
DECLARE @return_value INT
EXEC @return_value = [dbo].[SYS_ScriptAllTriggers] @InclDrop = 1
SELECT 'Return Value' = @return_value
GO
答案 4 :(得分:1)
使用syscomments可能并不总是有效。 syscomments的文本列限制为4000个字符。超过该触发器的触发器将被截断。您可能无法完全查看它。
答案 5 :(得分:0)
实际上,如果你查看sys.comments表,它有一个colid字段,它是一个数字列;如果它长于最大值,它将具有> 1的数字。如果你选择一个&gt; 1 colID并复制它们(如果有2条记录)它会给你整个触发器!
答案 6 :(得分:0)
将我自己的版本与此处和其他帖子中找到的答案结合使用(找不到原始问题。
select OBJECT_NAME(parent_obj) AS table_name,sysobj.name AS trigger_name,
[definition],'GO'
from sys.sql_modules m
inner join sysobjects sysobj on sysobj.id=m.object_id
INNER JOIN sys.tables t ON sysobj.parent_obj = t.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE sysobj.type = 'TR' and sysobj.name like 'NAME_OF_TRIGGER'
order by sysobj.name