如何动态创建审核表,保留源表中的数据类型,并为审核表创建插入、更新、删除触发器?
一种方法是使用以下代码。 这应该动态复制表,保留数据类型,并创建 INSERT、UPDATE、DELETE 触发器。
此触发器将在 UPDATE 上插入 2 条记录,一条“更新 - 插入”记录和一条“更新 - 删除”记录。 (这是商业规则。)
您需要更改“AUDIT_1”以将表前缀更改为您想要的任何内容。 感谢大家对这个问题的帮助。
DECLARE @TableName SYSNAME
DECLARE @SchemaName SYSNAME
DECLARE @SQL NVARCHAR(MAX) = 'CREATE TABLE ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME('TABLE_PREFIX' + SUBSTRING(@TableName, 3, LEN(@TableName)-2)) + ' (
[AuditId] INT IDENTITY(1,1) NOT NULL,
[AuditAction] VARCHAR(50) NOT NULL,
[AuditDateTime] DATETIME NOT NULL,
' +
STUFF((
SELECT ',' + '[' + c.name + '] ' +
CASE
WHEN c.system_type_id IN (167, 175, 231, 239) AND c.max_length = -1 THEN 'VARCHAR(MAX)'
WHEN c.system_type_id IN (167, 175, 231, 239) THEN 'VARCHAR(' + CAST(CASE WHEN c.max_length < 1 THEN 1 ELSE c.max_length END AS VARCHAR(5)) + ')'
WHEN c.system_type_id IN (165, 173, 231, 239) AND c.max_length = -1 THEN 'NVARCHAR(MAX)'
WHEN c.system_type_id IN (165, 173, 231, 239) THEN 'NVARCHAR(' + CAST(CASE WHEN c.max_length < 1 THEN 1 ELSE c.max_length / 2 END AS VARCHAR(5)) + ')'
WHEN c.system_type_id IN (40) THEN 'CHAR(' + CAST(CASE WHEN c.max_length < 1 THEN 1 ELSE c.max_length END AS VARCHAR(5)) + ')'
WHEN c.system_type_id IN (41) THEN 'NCHAR(' + CAST(CASE WHEN c.max_length < 1 THEN 1 ELSE c.max_length END AS VARCHAR(5)) + ')'
WHEN c.system_type_id IN (48, 52, 56) THEN 'INT'
WHEN c.system_type_id IN (127) THEN 'BIGINT'
WHEN c.system_type_id IN (59, 60, 62) THEN 'SMALLINT'
WHEN c.system_type_id IN (106) THEN CONCAT('DECIMAL(', [precision], ',', scale, ')')
WHEN c.system_type_id IN (108) THEN CONCAT('NUMERIC(', [precision], ',', scale, ')')
WHEN c.system_type_id = 104 THEN 'BIT' -- Changed from 'TINYINT' to 'BIT'
ELSE TYPE_NAME(c.system_type_id)
END +
CASE WHEN c.is_nullable = 1 THEN ' NULL' ELSE ' NOT NULL' END
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
ORDER BY c.column_id
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '')
+ ')'
EXEC(@SQL)
/* Create Trigger */
SET @SQL = 'CREATE TRIGGER [tg_' + @TableName + '_AUD1' +'] ON ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME(@TableName) +'
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT * FROM INSERTED)
BEGIN
IF EXISTS (SELECT * FROM DELETED)
BEGIN --UPDATE
INSERT INTO ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME('TABLE_PREFIX' + SUBSTRING(@TableName, 3, LEN(@TableName)-2))+ ' (
AuditAction,
AuditDateTime,
' + STUFF((
SELECT ',' + QUOTENAME(c.name)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
)
SELECT
''UPDATE - Inserted'',
SYSDATETIME(),
' + STUFF((
SELECT ',' + CASE WHEN c.name IN ('RowGuid', 'ModifiedDate') THEN 'DEFAULT' ELSE 'i.' + QUOTENAME(c.name) END
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
FROM inserted i;
INSERT INTO ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME('TABLE_PREFIX' + SUBSTRING(@TableName, 3, LEN(@TableName)-2))+ ' (
AuditAction,
AuditDateTime,
' + STUFF((
SELECT ',' + QUOTENAME(c.name)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
)
SELECT
''UPDATE - Deleted'',
SYSDATETIME(),
' + STUFF((
SELECT ',' + CASE WHEN c.name IN ('RowGuid', 'ModifiedDate') THEN 'DEFAULT' ELSE 'd.' + QUOTENAME(c.name) END
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
FROM deleted d;
END;
ELSE
BEGIN --INSERT
INSERT INTO ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME('TABLE_PREFIX' + SUBSTRING(@TableName, 3, LEN(@TableName)-2)) + ' (
AuditAction,
AuditDateTime,
' + STUFF((
SELECT ',' + QUOTENAME(c.name)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
)
SELECT
''INSERT'',
SYSDATETIME(),
' + STUFF((
SELECT ',' + CASE WHEN c.name IN ('RowGuid', 'ModifiedDate') THEN 'DEFAULT' ELSE 'i.' + QUOTENAME(c.name) END
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
FROM inserted i;
END;
END;
ELSE
BEGIN --DELETE
INSERT INTO ' + QUOTENAME(@SchemaName) + '.' + QUOTENAME('TABLE_PREFIX' + SUBSTRING(@TableName, 3, LEN(@TableName)-2))+ ' (
AuditAction,
AuditDateTime,
' + STUFF((
SELECT ',' + QUOTENAME(c.name)
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
)
SELECT
''DELETE'',
SYSDATETIME(),
' + STUFF((
SELECT ',' + CASE WHEN c.name IN ('RowGuid', 'ModifiedDate') THEN 'DEFAULT' ELSE 'd.' + QUOTENAME(c.name) END
FROM sys.columns c
WHERE c.object_id = OBJECT_ID(@SchemaName + '.' + @TableName)
FOR XML PATH(''), TYPE
).value('.[1]','nvarchar(max)'), 1, 1, '') + '
FROM deleted d;
END;
END'
EXEC(@SQL)
此外,如果您需要快速将触发器删除到审计表中,您可以使用以下代码快速实现。 此代码在名称中查找“AUDIT_1”。
/* CODE TO QUICKLY DROP ALL TRIGGERS IN SCHEMA */
DROP TABLE IF EXISTS #t1;
SELECT sch.name AS [Schema]
, t.name AS [Table]
, tr.name AS [Trigger]
, tr.is_disabled
, CASE tr.type WHEN 'TR' THEN 'SQL Trigger'
WHEN 'TA' THEN 'CLR Trigger' END AS [Trigger Type]
, tr.create_date
, tr.modify_date
, CASE WHEN tr.is_instead_of_trigger = 1 THEN 'INSTEAD OF' ELSE 'AFTER' END AS [Trigger Timing]
, CASE WHEN OBJECTPROPERTY(tr.object_id, 'ExecIsInsertTrigger') = 1 THEN 'INSERT,' ELSE '' END
+ CASE WHEN OBJECTPROPERTY(tr.object_id, 'ExecIsUpdateTrigger') = 1 THEN 'UPDATE,' ELSE '' END
+ CASE WHEN OBJECTPROPERTY(tr.object_id, 'ExecIsDeleteTrigger') = 1 THEN 'DELETE' ELSE '' END AS [Trigger Events]
INTO #t1
FROM sys.triggers AS tr
INNER JOIN sys.tables AS t ON tr.parent_id = t.object_id
INNER JOIN sys.schemas AS sch ON t.schema_id = sch.schema_id
WHERE sch.name LIKE 'field%' AND tr.name LIKE '%AUDIT_1';
SELECT 'DROP TRIGGER IF EXISTS ' + t1.[Trigger]
, *
FROM #t1 AS t1;
/* CODE TO QUICKLY DROP ALL AUDIT TABLES IN SCHEMA */
SELECT SCHEMA_NAME(t.schema_id) AS schema_name
, t.name AS table_name
INTO #t1
FROM sys.tables AS t
WHERE t.name LIKE 't_Audit%' AND SCHEMA_NAME(t.schema_id) LIKE 'Field%'
ORDER BY table_name
, schema_name;
SELECT *
, 'Drop table ' + t1.schema_name + '.' + t1.table_name
FROM #t1 AS t1
WHERE t1.table_name NOT LIKE '%Name%' OR t1.table_name NOT LIKE '%rows%';