Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

Compare dois esquemas e atualize o esquema antigo com as novas colunas do novo esquema


Uma ferramenta de comparação de esquema é uma boa ideia. O esquema de banco de dados é muito mais complicado do que a maioria das pessoas acredita, e cada diferença entre dois esquemas de banco de dados tem o potencial de causar bugs.

Se você ainda estiver interessado em fazer isso sozinho, a melhor abordagem que encontrei é extrair as definições de esquema para o texto e, em seguida, executar uma comparação de texto. Contanto que tudo seja classificado em ordem alfabética, você pode usar o recurso Comparar Documentos no Microsoft Word (ou FC.EXE, DIFF ou equivalente) para destacar as diferenças.

O script SQLPlus a seguir gera a definição do esquema em ordem alfabética, para permitir a comparação. Existem duas seções. A primeira seção lista cada coluna, no formato:
table_name.column_name: data_type = data_default <nullable>

A segunda seção lista índices e restrições, como segue:
PK constraint_name on table_name (pk_column_list)
FK constraint_name on table_name (fk_column_list)
CHECK constraint_name on table_name (constraint_definition)

O script serve como referência útil para extrair alguns detalhes do esquema Oracle. Este pode ser um bom conhecimento para se ter quando você estiver em sites de clientes e não tiver suas ferramentas usuais disponíveis, ou quando as políticas de segurança o impedirem de acessar um banco de dados de sites de clientes diretamente de seu próprio PC.
set serveroutput on;
set serveroutput on size 1000000;
declare
  rowcnt    pls_integer := 0;
  cursor c_column is
     select table_name, column_name, data_type, 
        data_precision, data_length, data_scale, 
        data_default, nullable,
        decode(data_scale, null, null, ',') scale_comma,
        decode(default_length, null, null, '= ') default_equals
      from all_tab_columns where owner = 'BCC'
      order by table_name, column_name;
  cursor c_constraint is
      select c.table_name, c.constraint_name,
         decode(c.constraint_type,
                'P','PK',
                'R','FK',
                'C','CHECK',
                 c.constraint_type) constraint_type,
         c.search_condition, 
         cc.column_1||cc.comma_2||cc.column_2||cc.comma_3||cc.column_3||cc.comma_4||cc.column_4||
         cc.comma_5||cc.column_5||cc.comma_6||cc.column_6||cc.comma_7||cc.column_7 r_columns   
       from all_constraints c,
          ( select owner, table_name, constraint_name, nvl(max(position),0) max_position,
             max( decode( position, 1, column_name, null ) ) column_1,
             max( decode( position, 2, decode(column_name, null, null, ',' ), null ) ) comma_2,
             max( decode( position, 2, column_name, null ) ) column_2,
             max( decode( position, 3, decode(column_name, null, null, ',' ), null ) ) comma_3,
             max( decode( position, 3, column_name, null ) ) column_3,
             max( decode( position, 4, decode(column_name, null, null, ',' ), null ) ) comma_4,
             max( decode( position, 4, column_name, null ) ) column_4,
             max( decode( position, 5, decode(column_name, null, null, ',' ), null ) ) comma_5,
             max( decode( position, 5, column_name, null ) ) column_5,
             max( decode( position, 6, decode(column_name, null, null, ',' ), null ) ) comma_6,
             max( decode( position, 6, column_name, null ) ) column_6,
             max( decode( position, 7, decode(column_name, null, null, ',' ), null ) ) comma_7,
             max( decode( position, 7, column_name, null ) ) column_7
           from all_cons_columns
           group by owner, table_name, constraint_name ) cc
       where c.owner = 'BCC'
       and c.generated != 'GENERATED NAME'
       and cc.owner = c.owner
       and cc.table_name = c.table_name
       and cc.constraint_name = c.constraint_name
       order by c.table_name, 
          decode(c.constraint_type,
                 'P','PK',
                 'R','FK',
                 'C','CHECK',
                 c.constraint_type) desc, 
          c.constraint_name;
begin
  for c_columnRow in c_column loop
    dbms_output.put_line(substr(c_columnRow.table_name||'.'||c_columnRow.column_name||': '||
                         c_columnRow.data_type||'('||
                         nvl(c_columnRow.data_precision, c_columnRow.data_length)||
                         c_columnRow.scale_comma||c_columnRow.data_scale||') '||
                         c_columnRow.default_equals||c_columnRow.data_default||
                         ' <'||c_columnRow.nullable||'>',1,255));
    rowcnt := rowcnt + 1;
  end loop;
  for c_constraintRow in c_constraint loop
    dbms_output.put_line(substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                         c_constraintRow.table_name||' ('||
                         c_constraintRow.search_condition||
                         c_constraintRow.r_columns||') ',1,255));
    if length(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                         c_constraintRow.table_name||' ('||
                         c_constraintRow.search_condition||
                         c_constraintRow.r_columns||') ') > 255 then
       dbms_output.put_line('... '||substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                            c_constraintRow.table_name||' ('||
                            c_constraintRow.search_condition||
                            c_constraintRow.r_columns||') ',256,251));
    end if;
    rowcnt := rowcnt + 1;
  end loop;
end;
/

Infelizmente, existem algumas limitações:
  1. Retornos de carro incorporados e espaços em branco em data_defaults, além de verificar as definições de restrição, podem ser destacados como diferenças, mesmo que tenham efeito zero no esquema.
  2. Não inclui chaves alternativas, índices exclusivos ou índices de desempenho. Isso exigiria uma terceira instrução SELECT no script, referenciando as visualizações de catálogo all_ind_columns e all_indexes.
  3. Não inclui detalhes de segurança, sinônimos, pacotes, gatilhos, etc. Os pacotes e gatilhos seriam melhor comparados usando uma abordagem semelhante à que você propôs originalmente. Outros aspectos da definição do esquema podem ser adicionados ao script acima.
  4. As definições de FK acima identificam as colunas de chave estrangeira de referência, mas não o PK ou a tabela que está sendo referenciada. Só mais um detalhe que nunca consegui fazer.

Mesmo se você não usar o script. Há um certo prazer técnico em brincar com essas coisas.;-)

Mateus