Question

I need to add a couple of columns to CDC for a table that is already being tracked. My approach is as follows:

EXEC sys.sp_cdc_drop_job 'capture'

BEGIN TRANSACTION

BEGIN TRY
    -- Copy existing data of the tracked table into a temporary table
    SELECT * INTO CDC.dbo_MyTable_Temp FROM CDC.dbo_MyTable_CT

    -- Add the new column to the temp table. This allows us to just use INSERT..SELECT * later
    ALTER TABLE CDC.dbo_MyTable_Temp ADD MyColumn INT NULL

    -- Disable CDC for the source table temporarily. This will drop the CDC table
    EXEC sys.sp_cdc_disable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable'

    -- Reenable CDC for the source table. This will recreate the table with the new columns
    EXEC sys.sp_cdc_enable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable', @supports_net_changes = 1, @role_name = NULL, @filegroup_name = 'CDCGROUP'

    -- Insert the old values into the CDC table
    INSERT INTO cdc.dbo_MyTable_CT SELECT * FROM cdc.dbo_MyTable_Temp

    -- Correct the start_lsn in CDC.change_tables. Otherwise all of the CDC stored procedures will be confused
    -- and although the old data will exist in the table the functions won't return it
    UPDATE cdc.change_tables SET start_lsn = (SELECT MIN(__$start_lsn) FROM cdc.dbo_MyTable_Temp) WHERE capture_instance = 'dbo_MyTable'

    -- Drop the temp table
    DROP TABLE cdc.dbo_MyTable_Temp

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION
    RAISERROR('Error!', 16, 1)
END CATCH

EXEC sys.sp_cdc_add_job 'capture'

However, when the job runs again after being re-added it generates an error that there is a violation of the primary key constraint on CDC.lsn_time_mapping.

Any suggestions?

Thanks!

Was it helpful?

Solution

I wasn't able to get to the exact cause of the error because the updates to the lsn_time_mapping happen in an extended stored procedure, but I was able to use different code to add the columns. Basically, I stuck to the CDC stored procedures instead of doing ALTER TABLE commands on the CDC table. The code is below:

-- Create a new capture instance for the table
EXEC sys.sp_cdc_enable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable_New', @supports_net_changes = 1, @role_name = NULL, @filegroup_name = 'CDCGROUP'

-- Copy all of the existing data from the old capture instance
INSERT INTO CDC.dbo_MyTable_New_CT SELECT *, NULL AS NewColumn1, NULL AS NewColumn2 FROM CDC.dbo_MyTable_CT

-- Disable the old capture instance
EXEC sys.sp_cdc_disable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable'

-- Now we need to jump through some hoops to rename the capture instance back to what it was:
-- Recreate a new capture instance with the old name again
EXEC sys.sp_cdc_enable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable', @supports_net_changes = 1, @role_name = NULL, @filegroup_name = 'CDCGROUP'

-- Copy all of the data over again
INSERT INTO CDC.dbo_MyTable_CT SELECT * FROM CDC.dbo_MyTable_New_CT

-- Remove the capture instance that we had been using to add the new columns
EXEC sys.sp_cdc_disable_table @source_schema = 'dbo', @source_name = 'MyTable', @capture_instance = 'dbo_MyTable_New'

-- We need to correct the start_lsn in the cdc.change_tables table. Otherwise all of the CDC stored procedures and views will be confused and
-- although the old data will exist in the CDC table it wouldn't be returned by those CDC procs
UPDATE cdc.change_tables SET start_lsn = (SELECT MIN(__$start_lsn) FROM cdc.dbo_MyTable_CT) WHERE capture_instance = 'dbo_MyTable'

Note that I'm performing this during downtime of the database. If you need to do this while the database is in use then you may need to add WHERE clauses to your insert statements so that you don't copy the same record from one table into a table where it already exists. When both capture instances are active any DML that affects the table will put rows into both capture instances.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top