Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Как да добавите ИЛИ пуснете колона от таблица с активиран CDC, без да губите данни в базата данни на SQL Server - урок за SQL Server

Сценарий:Изтегляне на скрипт

Понякога трябва да добавим или пуснем колона към таблицата с източник, за която вече е активирано улавянето на промяна на данни (CDC).
Новата добавена колона няма да бъде проследена от улавянето на промяна на данни (CDC), а за изпусната колона CDC таблицата ще show Null.

SP може да се използва за добавяне на нова колона към промяна на събирането на данни (CDC), без да се губят каквито и да било предишни данни в таблицата на CDC. Същият SP може да се използва за премахване на колона от Change Data Capture (CDC), тъй като тя се отстранява от колона източник, но оставя останалите колони без загуба на данни в CDC таблицата.


USE [DataBaseName]

GO

/*--------------------------------------------------------------------------------------------------------
How to Execute: EXEC usp_AddOrDropColumnToCDCTableWithoutLosingData @SchemaName,@TableName,@ColumnName,@Action

Adding New Column
Example :EXEC usp_AddOrDropColumnToCDCTableWithoutLosingData 'dbo','T','NAME','ADD'

Drop existing Column
Example :EXEC usp_AddOrDropColumnToCDCTableWithoutLosingData 'dbo','T','Name','DROP'

--------------------------------------------------------------------------------------------------------*/
SET ANSI_NULLS ON

GO

SET QUOTED_IDENTIFIER ON

GO

CREATE PROCEDURE dbo.Usp_addordropcolumntocdctablewithoutlosingdata @pSchemaName VARCHAR(50),
                                                                    @pTableName  VARCHAR(100),
                                                                    @pColumnName VARCHAR(100),
                                                                    @pAction     VARCHAR(10)
AS
  BEGIN
      DECLARE @vSQLTempTable NVARCHAR(MAX)
      DECLARE @vSQLAlterTable NVARCHAR(MAX)
      DECLARE @vDisableCDC NVARCHAR(MAX)
      DECLARE @vGetAlreadyExistingColumns NVARCHAR(MAX)
      DECLARE @vEnableCDC NVARCHAR(MAX)
      DECLARE @vLoadCDCTable NVARCHAR(MAX)
      DECLARE @vDropCreateTemp NVARCHAR(MAX)
      DECLARE @vDataType VARCHAR(50)
      DECLARE @vColumnList NVARCHAR(2000)
      DECLARE @vColumnExists INT
      DECLARE @vColumnExistsCDC INT
      DECLARE @vTempTableName VARCHAR(100)
      DECLARE @vDropColumnList NVARCHAR(2000)
      DECLARE @vDropColumnListExcSys NVARCHAR(2000)

      SET @vTempTableName='##' + @pSchemaName + '_' + @pTableName

      BEGIN TRY
          IF ( @pAction = 'ADD'
                OR @pAction = 'Drop' )
            BEGIN
                --Check if Column exists for SourceTable table
                SET @vColumnExists=(SELECT Count(*)
                                    FROM   INFORMATION_SCHEMA.COLUMNS
                                    WHERE  TABLE_SCHEMA = @pSchemaName
                                           AND TABLE_NAME = @pTableName
                                           AND COLUMN_NAME = @pColumnName)

                IF ( @vColumnExists = 0
                     AND @pAction = 'ADD' )
                  BEGIN
                      PRINT ' COLUMN ::' + @pColumnName
                            + ' does not exists for Source Table ::'
                            + @pTableName
                            + ' Please add column to Source Table to include in CDC Table.'
                  END
                ELSE
                  BEGIN
                      PRINT ' COLUMN ::' + @pColumnName
                            + ' exists for Source Table ::' + @pTableName
                            + '-->Proceeding to Next Step.'
                  END

                --Check if Column exists for CDC table
                IF ( @vColumnExists != 0
                     AND @pAction = 'ADD' )
                  SET @vColumnExistsCDC=(SELECT Count(*)
                                         FROM   INFORMATION_SCHEMA.COLUMNS
                                         WHERE  TABLE_SCHEMA = 'cdc'
                                                AND TABLE_NAME = @pSchemaName + '_' + @pTableName + '_CT'
                                                AND COLUMN_NAME = @pColumnName)

                IF ( @vColumnExistsCDC != 0
                     AND @pAction = 'ADD' )
                  BEGIN
                      PRINT ' COLUMN ::' + @pColumnName
                            + ' is already part of CDC Tble ::cdc.'
                            + @pSchemaName + '_' + @pTableName + 'CT'
                  END

                IF ( @vColumnExistsCDC = 0
                     AND @pAction = 'ADD' )
                  BEGIN
                      PRINT ' COLUMN ::' + @pColumnName
                            + ' is not part of CDC Tble ::cdc.'
                            + @pSchemaName + '_' + @pTableName
                            + 'CT -->Proceeding to ADD this column'
                  END

                --COPY EXISTING CDC TABLE TO TEMP TABLE
                --Drop Temp table before Creating/Loading IT
                SET @vDropCreateTemp=' IF Object_id(N''tempdb..'
                                     + @vTempTableName
                                     + ''') IS NOT NULL
                    BEGIN
                        DROP TABLE ##'
                                     + @pSchemaName + '_' + @pTableName + ' END'

                PRINT @vDropCreateTemp

                EXEC (@vDropCreateTemp)

                SET @vSQLTempTable= 'SELECT * INTO ' + @vTempTableName
                                    + ' From cdc.' + @pSchemaName + '_' + @pTableName
                                    + '_CT'

                PRINT @vSQLTempTable

                EXEC(@vSQLTempTable)

                IF ( @vColumnExistsCDC = 0
                     AND @pAction = 'ADD' )
                  BEGIN
                      --ADD COLUMN TO TEMP TABLE
                      SET @vDataType=(SELECT CASE
                                               WHEN DATA_TYPE IN ( 'CHAR', 'varchar', 'nvarchar' ) THEN DATA_TYPE + '('
                                                                                                        + Cast(CHARACTER_MAXIMUM_LENGTH AS VARCHAR(50))
                                                                                                        + ')'
                                               WHEN Data_Type IN ( 'int', 'bigint', 'smallint', 'tinyint',
                                                                   'money', 'bit', 'date', 'datetime' ) THEN Data_Type
                                               WHEN data_type IN ( 'numeric', 'decimal' ) THEN DATA_TYPE + '('
                                                                                               + Cast(Numeric_Precision_Radix AS VARCHAR(50))
                                                                                               + ',' + Cast(Numeric_scale AS VARCHAR(50))
                                                                                               + ')'
                                             END AS DataType
                                      FROM   INFORMATION_SCHEMA.COLUMNS
                                      WHERE  TABLE_NAME = @pTableName
                                             AND COLUMN_NAME = @pColumnName)
                      SET @vSQLAlterTable='ALTER TABLE ' + @vTempTableName + ' ADD '
                                          + @pColumnName + ' ' + @vDataType

                      PRINT @vSQLAlterTable

                      EXEC (@vSQLAlterTable)

                      -- ENABLE CDC ON TABLE ( INCLUDING NEW COLUMN)
                      IF Object_id(N'tempdb..##ColumnList') IS NOT NULL
                        BEGIN
                            DROP TABLE ##ColumnList
                        END

                      CREATE TABLE ##ColumnList
                        (
                           ColumnList NVARCHAR(2000)
                        )

                      SET @vGetAlreadyExistingColumns= N' DECLARE @vCDCAlreadyEnabledColumns NVARCHAR(2000)
                          SELECT @vCDCAlreadyEnabledColumns = COALESCE(@vCDCAlreadyEnabledColumns+ '','', '''')
                          + QUOTENAME(COLUMN_NAME) FROM  INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='''
                                                       + @pSchemaName + '_' + @pTableName + '_'
                                                       + 'CT'' AND COLUMN_NAME NOT
                                                   IN (''__$start_lsn'',
                                                   ''__$end_lsn'',
                                                   ''__$seqval'',
                                                   ''__$operation'',
                                                   ''__$update_mask'')
                                                   PRINT @vCDCAlreadyEnabledColumns
                                                   Insert into ##ColumnList values (@vCDCAlreadyEnabledColumns)'

                      PRINT @vGetAlreadyExistingColumns

                      EXEC ( @vGetAlreadyExistingColumns)

                      SELECT @vColumnList = ColumnList + ',[' + @pColumnName + ']'
                      FROM   ##ColumnList

                      PRINT @vColumnList

                      -- DISABLE CDC ON SOURCE TABLE
                      SET @vDisableCDC='EXEC sys.sp_cdc_disable_table @source_schema='''
                                       + @pSchemaName + ''',
         @source_name='''
                                       + @pTableName + ''',@capture_instance='''
                                       + @pSchemaName + '_' + @pTableName + ''''

                      PRINT @vDisableCDC

                      EXEC (@vDisableCDC)

                      --Enable CDC
                      SET @vEnableCDC='EXEC sys.sp_cdc_enable_table
         @source_schema=''' + @pSchemaName
                                      + ''',@source_name=''' + @pTableName
                                      + ''', @role_name=NULL, @captured_column_list= '''
                                      + @vColumnList + ''''

                      PRINT @vEnableCDC

                      EXEC (@vEnableCDC)

                      -- INSERT RECORD FROM Temp to CDC Table
                      SET @vLoadCDCTable=' INSERT INTO cdc.' + @pSchemaName + '_'
                                         + @pTableName
                                         + '_CT
                                      SELECT * FROM '
                                         + @vTempTableName + ''

                      --  Drop Table '+@vTempTableName+''
                      PRINT @vLoadCDCTable

                      EXEC (@vLoadCDCTable)
                  END

            /***-------------------------------------DROP COLUMN LOGIC STARTS-----------------------------************/
                --Build Column List excluding Drop column
                IF EXISTS (SELECT 1
                           FROM   INFORMATION_SCHEMA.COLUMNS
                           WHERE  TABLE_SCHEMA = 'cdc'
                                  AND TABLE_NAME = @pSchemaName + '_' + @pTableName + '_CT'
                                  AND COLUMN_NAME = @pColumnName)
                   AND @pAction = 'Drop'
                  BEGIN
                      SELECT @vDropColumnList = Stuff(o.COLUMNNAME, 1, 1, '')
                      FROM   INFORMATION_SCHEMA.COLUMNS t
                             CROSS APPLY (SELECT ',' + Column_Name + Char(10) AS [text()]
                                          FROM   INFORMATION_SCHEMA.COLUMNS c
                                          WHERE  c.Table_Name = t.Table_Name
                                                 AND c.COLUMN_NAME <> @pColumnName
                                          FOR XML PATH('')) o (COLUMNNAME)
                      WHERE  t.Table_Name = 'dbo_' + @pTableName + '_CT'

                      --Get Columns without Sytem Columns 
                      SELECT @vDropColumnListExcSys = Stuff(o.COLUMNNAME, 1, 1, '')
                      FROM   INFORMATION_SCHEMA.COLUMNS t
                             CROSS APPLY (SELECT ',' + Column_Name + Char(10) AS [text()]
                                          FROM   INFORMATION_SCHEMA.COLUMNS c
                                          WHERE  c.Table_Name = t.Table_Name
                                                 AND c.COLUMN_NAME <> @pColumnName
                                                 AND C.COLUMN_NAME NOT IN ( '__$start_lsn', '__$end_lsn', '__$seqval', '__$operation', '__$update_mask' )
                                          FOR XML PATH('')) o (COLUMNNAME)
                      WHERE  t.Table_Name = 'dbo_' + @pTableName + '_CT'

                      -- DISABLE CDC for Drop Column
                      SET @vDisableCDC='EXEC sys.sp_cdc_disable_table @source_schema='''
                                       + @pSchemaName + ''',
         @source_name='''
                                       + @pTableName + ''',@capture_instance='''
                                       + @pSchemaName + '_' + @pTableName + ''''

                      EXEC (@vDisableCDC)

                      -- ENABLE TABLE EXCLUDING GIVEN COLUMN
                      SET @vEnableCDC='EXEC sys.sp_cdc_enable_table
         @source_schema=''' + @pSchemaName
                                      + ''',@source_name=''' + @pTableName
                                      + ''', @role_name=NULL, @captured_column_list= '''
                                      + @vDropColumnListExcSys + ''''

                      EXEC (@vEnableCDC)

                      --COPY DATA FROM TEMP DATA TO CDC TABLE
                      SET @vLoadCDCTable=' INSERT INTO cdc.' + @pSchemaName + '_'
                                         + @pTableName + '_CT(' + @vDropColumnList
                                         + ')
                                      SELECT '
                                         + @vDropColumnList + ' FROM ' + @vTempTableName
                                         + ''

                      --Drop Table '+@vTempTableName+''
                      EXEC (@vLoadCDCTable)
                  END
            END
          ELSE
            PRINT ' ADD OR Drop are the correct actions available for this Procedure.Please provide ADD or Drop for SP Signature'
      END TRY

      BEGIN CATCH
          ROLLBACK

          PRINT ' ERROR Occured and All Transactions are rolledback.'
      END CATCH
  END

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Типове курсори на SQL Server - Статичен курсор само за препращане | Урок за SQL Server / Урок за TSQL

  2. Какво е @@SERVICENAME в SQL Server?

  3. Връщане на броя на редовете, засегнати от операторите UPDATE

  4. Нови функции в SQL Server 2017 (Database Engine)

  5. Преобразуване на дата и култура:Разлика между DATE и DATETIME