而不是所有表上的插入触发器
Posted
技术标签:
【中文标题】而不是所有表上的插入触发器【英文标题】:Instead of Trigger for Insert on all tables 【发布时间】:2011-07-01 17:57:23 【问题描述】:有人可以提供有关如何为数据库中的所有表编写通用而不是触发器的源代码。我想运行存储过程,它将为 db 中的所有表创建而不是插入触发器。
【问题讨论】:
还是不明白触发点。除了将值插入基表之外,他们还会做什么? 【参考方案1】:不了解为什么要在每个表上都使用而不是触发器,以及除了将提供的值插入基表之外,您还打算在结果代码中做什么(就像如果没有而不是触发器),这就是我想出的。您会注意到,如果触发器已经存在,它会删除它,因此您可以在同一个数据库中多次运行它而不会出现“已经存在”错误。它忽略 IDENTITY、ROWGUIDCOL、计算列和 TIMESTAMP/ROWVERSION 列。最后,我将展示如何快速检查,而不是执行(已注释掉)输出脚本(最大 8K),如果您想查看更多内容(最大 64K),将其转换为 XML。不能保证您可以根据表/列的数量在 SSMS 中返回整个内容。如果您想检查和/或手动运行它,您可能需要创建一个存储值的表 - 然后您可以使用应用程序或您拥有的东西将其拉出。现在,如果您希望它自动执行,您可以按照 Yuck 的观点 - 将其保存为存储过程并创建响应某些 DDL 事件(CREATE TABLE 等)的 DDL 触发器。
SET NOCOUNT ON;
DECLARE
@cr char(2) = char(13) + char(10),
@t char(1) = char(9),
@s nvarchar(max) = N'';
;WITH t AS
(
SELECT [object_id],
s = OBJECT_SCHEMA_NAME([object_id]),
n = name
FROM sys.tables WHERE is_ms_shipped = 0
)
SELECT @s += 'IF OBJECT_ID(N''dbo.ioTrigger_' + t.s + '_' + t.n + ''')
IS NOT NULL
BEGIN
DROP TRIGGER dbo.[ioTrigger_' + t.s + '_' + t.n + '];
END
G' + 'O
CREATE TRIGGER ioTrigger_' + t.s + '_' + t.n + '
ON ' + QUOTENAME(t.s) + '.' + QUOTENAME(t.n) + '
INSTEAD OF INSERT
AS
BEGIN
SET NOCOUNT ON;
-- surely you must want to put some other code here?
INSERT ' + QUOTENAME(t.s) + '.' + QUOTENAME(t.n) + '
(
' +
(
SELECT @t + @t + name + ',' + @cr
FROM sys.columns AS c
WHERE c.[object_id] = t.[object_id]
AND is_identity = 0
AND is_rowguidcol = 0
AND is_computed = 0
AND system_type_id <> 189
FOR XML PATH(''), TYPE
).value(N'./text()[1]', N'nvarchar(max)') + '--'
+ @cr + @t + ')'
+ @cr + @t + 'SELECT
' +
(
SELECT @t + @t + name + ',' + @cr
FROM sys.columns AS c
WHERE c.[object_id] = t.[object_id]
AND is_identity = 0
AND is_rowguidcol = 0
AND is_computed = 0
AND system_type_id <> 189
FOR XML PATH(''), TYPE
).value(N'./text()[1]', N'nvarchar(max)') + '--'
+ @cr + @t + 'FROM
inserted;
END' + @cr + 'G' + 'O' + @cr
FROM t
ORDER BY t.s, t.n;
SELECT @s = REPLACE(@s, ',' + @cr + '--' + @cr, @cr);
-- you can inspect at least part of the script by running the
-- following in text mode:
SELECT @s;
-- if you want to see more of the whole thing (but not necessarily
-- the whole thing), run this in grid mode and click on the result:
SELECT CONVERT(XML, @s);
几个注意事项:
我不处理稀疏列、xml 集合、文件流等。因此,如果您有精美的表,您可能会遇到其中一些功能的复杂性。
触发器的名称并没有真正“受保护”——你可以有一个名为 foo 的模式,另一个名为 foo_bar 的模式,然后 foo 中的一个名为 bar_none 的表和 foo_bar 中的一个名为 none 的表。这将导致重复的触发器名称,因为我使用下划线作为分隔符。我向 CDC 投诉了这个问题,但微软以“无法修复”为由关闭了该错误。如果您碰巧使用带下划线的模式,请记住一些事情。
【讨论】:
这让我朝着我想要的方向开始。谢谢。【参考方案2】:您只能在 SQL Server 2008+ 中为 DDL 语句创建数据库触发器。
如果您需要在数据库中的每个表上使用 DML 触发器 (INSTEAD OF INSERT
),您将不得不自己管理它们或尝试创建数据库级 DDL 触发器然后负责在任何CREATE
或ALTER
表语句上创建或更新INSTEAD OF INSERT
触发器。可能会很麻烦,而且几乎肯定需要使用动态 SQL。
出于好奇,您是否正在尝试建立某种审计机制?
【讨论】:
如果审计是目标,那么我怀疑 SQL Server 审计,或者至少是 CDC 或变更跟踪,将是一种不那么具有侵入性和问题的方法。但是,其中一些是特定于版本的。 @Aaron:在得到保证之前不要太离题,但我个人更喜欢 SQL 数据库中的解决方案。我已经为我自己的许多项目修改了类似于weblogs.asp.net/jgalloway/archive/2008/01/27/… 的脚本。当然,你说的没有错。以上是关于而不是所有表上的插入触发器的主要内容,如果未能解决你的问题,请参考以下文章