SQL Server - 如何动态创建审核表、保留数据类型并创建插入、更新、删除触发器

问题描述 投票:0回答:1

如何动态创建审核表,保留源表中的数据类型,并为审核表创建插入、更新、删除触发器?

(写这个问题是为了向其他人发布答案,以防有帮助。)

sql-server t-sql
1个回答
0
投票

一种方法是使用以下代码。 这应该动态复制表,保留数据类型,并创建 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 '%fields%' OR t1.table_name NOT LIKE '%rows%';
© www.soinside.com 2019 - 2024. All rights reserved.