Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como criar exibições de histórico OU de auditoria de tabelas de Change Data Capture (CDC) no SQL Server - Tutorial do SQL Server

Cenário:

Você está trabalhando como DBA ou desenvolvedor do SQL Server, você habilitou o Change Data Capture em um dos Bancos de Dados do SQL Server.

Solução:

O script abaixo criará uma visualização para cada uma das tabelas em que o CDC está habilitado em seu banco de dados. Eu usei o Esquema de Auditoria, antes de executar o script, Você precisa criar o Esquema de Auditoria ou Se você deseja criar visualizações no Esquema Hist, altere Esquema no código abaixo da auditoria para o histórico.
Cada exibição nos retornará abaixo das colunas
  • Commit_Time,
  • Nome_coluna,
  • Old_Value,
  • New_Value,
  • Modificado por




IF OBJECT_ID(N'tempdb..##CDC_TableList') IS NOT NULL
BEGIN
    DROP TABLE ##CDC_TableList
END

SELECT T.name AS TableName,
       C.name AS ColumnName,
       'CASE WHEN (sys.Fn_cdc_is_bit_set (sys.Fn_cdc_get_column_ordinal (''dbo_'
       + T.name + ''',''' + C.name+
       + '''),__$update_mask) = 1) THEN Cast('
       + C.Name
       + ' AS SQL_VARIANT) ELSE NULL END AS '
       + C.name  AS CaseStm INTO ##CDC_TableList
 FROM   sys.tables T
       INNER JOIN sys.columns c
               ON T.OBJECT_ID = c.OBJECT_ID
WHERE  is_tracked_by_cdc = 1
       AND c.is_identity = 0
       AND C.name NOT IN ( 'CreatedBy', 'CreatedDate', 'ModifiedBy', 'ModifiedDate' )
       AND T.TYPE='U'
       AND T.is_ms_shipped<>1
      
      -- Select * from sys.tables

DECLARE @TableName NVARCHAR(200)
DECLARE cdc_cursor CURSOR FOR 
SELECT DISTINCT TableName FROM ##CDC_TableList
OPEN cdc_cursor 
FETCH NEXT FROM cdc_cursor INTO @TableName

WHILE @@FETCH_STATUS = 0 
BEGIN

DECLARE @ColumnList  NVARCHAR(MAX)
DECLARE @CaseStmList NVARCHAR(MAX)
DECLARE @SQL_Stm  NVARCHAR(MAX)
DECLARE @SQL_Stm_DropView  NVARCHAR(MAX)
PRINT @TableName

 SELECT @ColumnList = STUFF(o.COLUMNNAME, 1, 1, '')
 FROM ##CDC_TableList t CROSS APPLY  (SELECT ',' + ColumnName+CHAR(10) AS [text()]
            FROM  ##CDC_TableList c
            WHERE    c.TableName = t.TableName
            FOR XML PATH('')) o (COLUMNNAME)
 WHERE t.TableName=@TableName
 PRINT @ColumnList
 
 SELECT @CaseStmList = STUFF(o.COLUMNNAME, 1, 1, '')
 FROM ##CDC_TableList t CROSS APPLY  (SELECT ',' + CaseStm+CHAR(10) AS [text()]
            FROM  ##CDC_TableList c
            WHERE    c.TableName = t.TableName
            FOR XML PATH('')) o (COLUMNNAME)
 WHERE t.TableName=@TableName
 --PRINT @CaseStmList


--If using Other Schema than AUDIT THEN change to that.
SET @SQL_Stm=' CREATE VIEW AUDIT.vw_'+@TableName+' AS

SELECT sys.Fn_cdc_map_lsn_to_time(up_b.__$start_lsn) AS Commit_Time, up_b.Column_Name, up_b.Old_Value, up_a.New_Value,up_a.ModifiedBy
FROM
    ( SELECT __$start_lsn, column_name, old_value,ModifiedBy
   FROM (SELECT __$start_lsn,'+@CaseStmList+',ModifiedBy FROM cdc.fn_cdc_get_all_changes_dbo_'+@TableName+'( sys.fn_cdc_get_min_lsn(''dbo_'+@TableName+'''), sys.fn_cdc_map_time_to_lsn(''largest less than or equal'',GETDATE()), N''all update old'')
 WHERE __$operation = 3
  ) AS BeforeUpdate
  UNPIVOT (old_value FOR column_name IN ('+@ColumnList+') ) AS unp) AS up_b INNER JOIN
  (SELECT __$start_lsn, column_name, new_value,ModifiedBy
   FROM (SELECT __$start_lsn,'+@CaseStmList+',ModifiedBy FROM cdc.fn_cdc_get_all_changes_dbo_'+@TableName+'(sys.fn_cdc_get_min_lsn(''dbo_'+@TableName+'''), sys.fn_cdc_map_time_to_lsn(''largest less than or equal'',GETDATE()), N''all'')
    WHERE __$operation = 4
   ) AS AfterUpdate
   UNPIVOT (new_value FOR column_name IN ('+@ColumnList+') ) AS unp ) AS up_a
ON up_b.__$start_lsn = up_a.__$start_lsn AND up_b.column_name = up_a.column_name'
--Drop View if already exists
SET @SQL_Stm_DropView= 'IF EXISTS (SELECT TABLE_NAME FROM INFORMATION_SCHEMA.VIEWS
         WHERE TABLE_NAME = ''vw_'+@TableName+''')
   DROP VIEW AUDIT.vw_'+@TableName
   PRINT @SQL_Stm_DropView

EXEC (@SQL_Stm_DropView)
EXEC ( @SQL_Stm)
FETCH NEXT FROM cdc_cursor INTO @TableName
END 

CLOSE cdc_cursor 
DEALLOCATE cdc_cursor