Create Audit Trail from SQL CDC

Ajeet Singh 71 Reputation points
2022-03-21T23:35:58.377+00:00

I have a few tables on which I have enabled CDC. As each row in CDC table contains all the columns regardless if they were changed or not, so it becomes difficult to figure out only the changed data. Is there a way to create a single Audit Table with data in these CDC tables so that it shows Table Name, Column Name, Old Value, New Value from all CDC tables together. If this is possible then a better reporting can be done.

Thanks

Azure SQL Database
0 comments No comments

2 answers

Sort by: Most helpful
  1. Anurag Sharma 17,636 Reputation points
    2022-03-22T10:23:10.337+00:00

    Hi @Ajeet Singh , welcome to Microsoft Q&A forum.

    As I understand you want to capture the CDC tables records in the form of old values and new values for changed columns.

    Actually there is no direct way of doing it as CDC enabled tables return 2 rows one for old value and one for new value and we need to do PIVOT to change the rows to column value. However based on below article I added one extra column in the script which could achieve something similar to it:

    USING UNPIVOT WITH CDC FUNCTIONS TO GET UPDATED COLUMNS LIST

    This looks a little complex but if we read through it, it is following same pattern of getting older values and newer values and then pivoting it. Below is an example of tables with 3 columns but you can keep on adding the columns based on table. Again this is limited to one table a time.

    DECLARE @from_lsn binary(10), @to_lsn binary(10);    
    SET @from_lsn = sys.fn_cdc_get_min_lsn('SalesLT_ProductModel');    
    SET @to_lsn   = sys.fn_cdc_get_max_lsn();    
    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  
    FROM(  
    SELECT __$start_lsn, column_name, old_value  
        FROM (SELECT __$start_lsn,  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','Name'),__$update_mask) = 1) THEN CAST([Name] as sql_variant)   
     ELSE NULL END AS [Name],  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','ProductModelID'),__$update_mask) = 1) THEN CAST ([ProductModelID] as sql_variant)   
     ELSE NULL END AS [ProductModelID],  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','ModifiedDate'),__$update_mask) = 1) THEN CAST ([ModifiedDate] as sql_variant)   
     ELSE NULL END AS [ModifiedDate]  
        FROM [cdc].[fn_cdc_get_all_changes_SalesLT_ProductModel](@from_lsn, @to_lsn, N'all update old')  
        WHERE __$operation = 3)as t1  
        UNPIVOT (old_value FOR column_name IN ([Name], [ProductModelID],[ModifiedDate]) ) as unp  ) as up_b   
     INNER JOIN  
     (SELECT __$start_lsn, column_name, new_value  
        FROM (SELECT __$start_lsn,  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','Name'),__$update_mask) = 1) THEN CAST([Name] as sql_variant)   
     ELSE NULL END AS [Name],  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','ProductModelID'),__$update_mask) = 1) THEN CAST ([ProductModelID] as sql_variant)  
     ELSE NULL END AS [ProductModelID],  
        CASE WHEN (sys.fn_cdc_is_bit_set (sys.fn_cdc_get_column_ordinal ('SalesLT_ProductModel','ModifiedDate'),__$update_mask) = 1) THEN CAST ([ModifiedDate] as sql_variant)  
     ELSE NULL END AS [ModifiedDate]  
        FROM [cdc].[fn_cdc_get_all_changes_SalesLT_ProductModel](@from_lsn, @to_lsn, N'all') -- 'all update old' is not necessary here  
        WHERE __$operation = 4) as t2  
        UNPIVOT (new_value FOR column_name IN ([Name], [ProductModelID],[ModifiedDate]) ) as unp) as up_a  
     ON up_b.__$start_lsn = up_a.__$start_lsn AND up_b.column_name = up_a.column_name  
    

    Output:

    185624-image.png

    Please let us know if this helps or else we can discuss further.

    ----------

    If answer is helpful please please click on 185632-image.png as it could help other members of the Microsoft Q&A community who have similar questions and are looking for solutions. Thank you for helping to improve Microsoft Q&A!

    Was this answer helpful?

    1 person found this answer helpful.

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.

    2 deleted comments

    Comments have been turned off. Learn more

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.