I need to get all the tables that were changed in a database, including the rows' IDs that were updated/added/removed.
So, if I have table table1
and table2
, and rows with ID 15 and 16 were changed in table1
, and rows with IDs 200 and 201 were changed in table2
, I want to run a script that returns:
+-----------+-------+
| tableName | rowId |
+-----------+-------+
| table1 | 15 |
| table1 | 16 |
| table2 | 200 |
| table2 | 201 |
+-----------+-------+
I managed to find this script:
set nocount on;
-- We want to check for changes since the previous version
--declare @prevTrackingVersion int = INSERT_YOUR_PREV_VERSION_HERE
-- Comment out this line if you know the previous version
declare @prevTrackingVersion int = CHANGE_TRACKING_CURRENT_VERSION() - 1
-- Get a list of table with change tracking enabled
declare @trackedTables as table (name nvarchar(1000));
insert into @trackedTables (name)
select sys.tables.name from sys.change_tracking_tables
join sys.tables ON tables.object_id = change_tracking_tables.object_id
-- This will be the list of tables with changes
declare @changedTables as table (name nvarchar(1000));
-- For each table name in tracked tables
declare @tableName nvarchar(1000)
while exists(select top 1 * from @trackedTables)
begin
-- Set the current table name
set @tableName = (select top 1 name from @trackedTables order by name asc);
print @tableName
-- Determine if the table has changed since the previous version
declare @sql nvarchar(250)
declare @retVal int
set @sql = 'select @retVal = count(*) from changetable(changes ' + @tableName + ', ' + cast(@prevTrackingVersion as varchar) + ') as changedTable'
exec sp_executesql @sql, N'@retVal int output', @retVal output
print @retVal
if @retval > 0
begin
insert into @changedTables (name) select @tableName
end
-- Delete the current table name
delete from @trackedTables where name = @tableName;
end
select * from @changedTables;
However, it only outputs the names of the tables that were modified.
So, I know that this command:
SELECT * FROM CHANGETABLE(CHANGES table1, 0) as CT;
outputs this:
+----------------------+----+
| SYS_CHANGE_OPERATION | ID |
+----------------------+----+
| I | 15 |
| I | 16 |
+----------------------+----+
In the script, this same command is used:
set @sql = 'select @retVal = count(*) from changetable(changes ' + @tableName + ', ' + cast(@prevTrackingVersion as varchar) + ') as changedTable'
but it only gets the count, and then checks if it is greater than 0 (if there is any modifications for this table):
if @retval > 0
begin
insert into @changedTables (name) select @tableName
end
However, as mentioned, I need to not only get the tables modified, but the IDs of the rows that were modified.
I feel like I need to JOIN, but I'm not really sure how to work this out.
Thanks
What you need to do is -
Try to run CHANGETABLE for one table can help you understand what I am saying -
select *
from CHANGETABLE(CHANGES your_table, 0 /*track version*/) chg
To keep things simple, I assume all your tracking tables have single-column PK. You can find out tracking tables and their PKs by -
select c.table_name
,k.column_name pk
from sys.change_tracking_tables t
,information_schema.table_constraints c
,information_schema.key_column_usage k
where object_name(t.object_id) = c.table_name
and c.constraint_type = 'PRIMARY KEY'
and c.table_name = k.table_name
and c.constraint_name = k.constraint_name
Here is the whole modified script -
set nocount on;
-- We want to check for changes since the previous version
--declare @prevTrackingVersion int = INSERT_YOUR_PREV_VERSION_HERE
-- Comment out this line if you know the previous version
declare @prevTrackingVersion int CHANGE_TRACKING_CURRENT_VERSION() - 1
-- Get a list of table with change tracking enabled
declare @trackedTables as table (table_name nvarchar(100), pk nvarchar(100));
insert into @trackedTables (table_name, pk)
select c.table_name
,k.column_name pk
from sys.change_tracking_tables t
,information_schema.table_constraints c
,information_schema.key_column_usage k
where object_name(t.object_id) = c.table_name
and c.constraint_type = 'PRIMARY KEY'
and c.table_name = k.table_name
and c.constraint_name = k.constraint_name
-- This will be the list of changes
declare @changes as table (table_name varchar(100), pk varchar(100))
-- For each table name in tracked tables
declare @table_name nvarchar(100)
,@pk nvarchar(100)
while exists(select top 1 * from @trackedTables)
begin
-- Set the current table name
select top 1 @table_name = table_name, @pk = pk from @trackedTables order by table_name asc;
insert into @changes (table_name, pk)
exec ('select ''' + @table_name + ''', ' + @pk + ' from CHANGETABLE(CHANGES ' + @table_name + ', ' + @prevTrackingVersion + ') chg')
-- Delete the current table name
delete from @trackedTables where table_name = @table_name;
end
select * from @changes;