quinta-feira, 18 de fevereiro de 2016

Equalizar tabelas tomando como base um banco de dados

Olá a todos!

Já deve ter acontecido contigo: precisar mandar um script de BD para algum cliente mas ninguém faz idéia da versão que o banco de dados do cliente está.
Enfim, já passei por isso diversas vezes e tinha que assumir que o banco de homologação interno da empresa seria o correto. Então eu fiz esse script para tentar simplificar (um pouco) a minha vida ao equalizar tabelas de clientes. Segue abaixo o código:

 /******************************************************************************  
 Objective...: Gerar um script de equalização tomando como base um database.  
 Author......: Paulo E. Scatena  
 Date........: 2015-04-05  
 *******************************************************************************/  
 /*Prefixo de tabelas - para gerar script somente de um range específico de tabelas   
 (por nome de objeto)*/  
 DECLARE @PREFIXO VARCHAR(10) = ''  
 SET NOCOUNT ON  
 DECLARE @T_NAME VARCHAR(255),  
           @C_NAME VARCHAR(255),  
           @C_TYPE VARCHAR(255),  
           @C_ISNL VARCHAR(3),  
           @C_LENC INT,  
           @C_LENN     INT,  
           @C_LENP     INT,  
           @C_DEF VARCHAR(255),  
           @C_COLL VARCHAR(255),   
           @U_TBL VARCHAR(255) = '',  
           @C_1ST BIT = 1,   
           @LINE_SEM_DF VARCHAR(MAX),  
           @IDT BIT = 0  
 CREATE TABLE #T_T (L BIGINT IDENTITY(1,1), LINE VARCHAR(5000))  
 CREATE TABLE #T_C (L BIGINT IDENTITY(1,1), TBL VARCHAR(255), LINE VARCHAR(5000))  
 DECLARE CUR_COLUMNS CURSOR FAST_FORWARD FOR            
 SELECT ISNULL(T.TABLE_NAME, ''),   
        ISNULL(COLUMN_NAME, ''),   
        ISNULL(DATA_TYPE, ''),   
        ISNULL(IS_NULLABLE, ''),   
        ISNULL(CHARACTER_MAXIMUM_LENGTH, 0),   
        ISNULL(NUMERIC_PRECISION, 0),   
        ISNULL(NUMERIC_SCALE, 0),   
        ISNULL(COLUMN_DEFAULT, ''),   
        ISNULL(COLLATION_NAME, ''),  
        CASE WHEN EXISTS(SELECT 1 FROM sys.identity_columns WHERE name = C.COLUMN_NAME) then 1 else 0 end  
 FROM INFORMATION_SCHEMA.COLUMNS C INNER JOIN INFORMATION_SCHEMA.TABLES T ON  
 (C.TABLE_NAME = T.TABLE_NAME)  
 AND T.TABLE_TYPE = 'BASE TABLE'  
 AND (ISNULL(@PREFIXO, '') = '' OR T.TABLE_NAME LIKE '%' + @PREFIXO + '%')  
 AND T.TABLE_NAME NOT LIKE 'SYS%'  
 ORDER BY T.TABLE_NAME  
 OPEN CUR_COLUMNS  
 FETCH NEXT FROM CUR_COLUMNS INTO  
      @T_NAME,  
      @C_NAME,   
      @C_TYPE,   
      @C_ISNL,   
      @C_LENC,  
      @C_LENN,  
      @C_LENP,  
      @C_DEF,  
      @C_COLL,  
      @IDT  
 WHILE @@FETCH_STATUS = 0  
 BEGIN  
      /*Parte do Create Table*/  
      IF(@T_NAME <> @U_TBL)  
      BEGIN  
           IF(@U_TBL <> '')  
                INSERT INTO #T_T(LINE) VALUES (')')  
           SET @C_1ST = 1  
           INSERT INTO #T_T(LINE) VALUES('IF(NOT EXISTS(SELECT 1 FROM SYSOBJECTS WHERE ID = OBJECT_ID(''' + ISNULL(@T_NAME, '') + ''')))')  
           INSERT INTO #T_T(LINE) VALUES('CREATE TABLE DBO.' + ISNULL(@T_NAME, '') + '(')       
      END  
      DECLARE @LINE VARCHAR(5000)  
      DECLARE @NN VARCHAR(20) = ''  
      DECLARE @DF VARCHAR(100) = ''  
      DECLARE @SZ VARCHAR(30) = ''  
      DECLARE @CN VARCHAR(100) = ''  
      DECLARE @IDENT VARCHAR(100) = ''  
      IF(@C_TYPE NOT IN ('int', 'datetime', 'bit', 'bigint', 'tinyint', 'text', 'uniqueidentifier',   
           'money', 'smalldatetime', 'smallint', 'image', 'binary'))  
      BEGIN  
           SET @SZ = '(' + LTRIM(RTRIM(  
                CASE WHEN @C_LENN <> 0 THEN STR(@C_LENN)   
                      WHEN @C_LENC <> 0 THEN  
                          CASE WHEN @C_LENC <> -1 THEN STR(@C_LENC) ELSE 'MAX' END  
                END +   
                     CASE WHEN ISNULL(@C_LENP, 0) <> 0 THEN ',' + LTRIM(RTRIM(STR(@C_LENP))) ELSE '' END)) +   
                ')'  
      END  
      SET @NN = CASE WHEN @C_ISNL = 'NO' THEN 'NOT NULL' ELSE '' END  
      SET @DF = CASE WHEN @C_ISNL = 'YES' AND @C_DEF = '' THEN  
                ' DEFAULT ' +   
                CASE   
                     WHEN @C_TYPE IN ('varbinary', 'binary', 'int', 'numeric', 'money', 'smallint', 'bigint', 'decimal') THEN '0'  
                     WHEN @C_TYPE IN ('datetime', 'smalldatetime') THEN '(getdate())'  
                ELSE ''' '''  
                END  
           ELSE  
                CASE WHEN @C_ISNL = 'YES' AND @C_DEF <> '' THEN   
                     CASE WHEN @C_DEF NOT LIKE '%NULL%' THEN     ' DEFAULT ' + @C_DEF ELSE 'DEFAULT '' ''' END  
                ELSE  
                     ' '  
                END  
           END  
      SET @CN = CASE WHEN @C_COLL <> '' THEN 'COLLATE ' + @C_COLL ELSE '' END  
      SET @LINE = @C_NAME + ' ' + @C_TYPE + ' ' +   
           CASE WHEN @SZ <> '' THEN @SZ ELSE '' END + ' ' +   
           CASE WHEN @CN <> '' THEN @CN ELSE '' END + ' ' +   
           CASE WHEN @DF <> '' THEN @DF ELSE '' END + ' ' +             
           CASE WHEN @NN <> '' THEN @NN ELSE '' END + ' '  
      SET @IDENT = CASE WHEN @IDT = 1 THEN ' IDENTITY(1,1)' ELSE '' END   
      -- No alter table, o comando vai sem NOT NULL e nem default pois é só para equalizar banco  
      SET @LINE_SEM_DF = @C_NAME + ' ' + @C_TYPE + ' ' +   
           CASE WHEN @SZ <> '' THEN @SZ ELSE '' END + ' ' +   
           @IDENT +  
           CASE WHEN @CN <> '' THEN @CN ELSE '' END + ' '        
      INSERT INTO #T_T(LINE) VALUES(  
           CASE WHEN @C_1ST = 0 THEN ',' ELSE '' END +     @LINE)  
      INSERT INTO #T_C(TBL, LINE) VALUES (@T_NAME, 'IF(NOT EXISTS(SELECT 1 FROM SYSCOLUMNS WHERE ID = OBJECT_ID(''' + @T_NAME + ''') AND NAME = ''' + @C_NAME + '''))')  
      INSERT INTO #T_C(TBL, LINE) VALUES(@T_NAME, 'ALTER TABLE [' + @T_NAME + '] ADD ' + @LINE_SEM_DF)  
      INSERT INTO #T_C(TBL, LINE) VALUES(@T_NAME, 'GO')  
      SET @U_TBL = @T_NAME  
      SET @C_1ST = 0  
 FETCH NEXT FROM CUR_COLUMNS INTO  
      @T_NAME,  
      @C_NAME,   
      @C_TYPE,   
      @C_ISNL,   
      @C_LENC,  
      @C_LENN,  
      @C_LENP,  
      @C_DEF,  
      @C_COLL,  
      @IDT  
 END  
 CLOSE CUR_COLUMNS  
 DEALLOCATE CUR_COLUMNS       
 INSERT INTO #T_T(LINE) VALUES (')')  
 PRINT '/*Criação de tabelas - Table Creation*/'  
 SELECT LINE FROM #T_T  
 ORDER BY L  
 PRINT '/*Ajustes de tabelas - Column Adjustments*/'  
 SELECT LINE FROM #T_C  
 ORDER BY L  
 DROP TABLE #T_T  
 DROP TABLE #T_C  
 SET NOCOUNT OFF  


Espero que ajude!

Grande abraço e até a próxima!

Nenhum comentário: