sql >> Base de Datos >  >> RDS >> Oracle

Compare dos esquemas y actualice el esquema antiguo con las nuevas columnas del nuevo esquema

Una herramienta de comparación de esquemas es una buena idea. El esquema de la base de datos es mucho más complicado de lo que la mayoría de la gente cree, y cada diferencia entre dos esquemas de base de datos tiene el potencial de causar errores.

Si todavía está interesado en hacerlo usted mismo, el mejor enfoque que he encontrado es extraer las definiciones del esquema al texto y luego ejecutar una comparación de texto. Siempre que todo esté ordenado alfabéticamente, puede usar la función Comparar documentos en Microsoft Word (o FC.EXE, DIFF o equivalente) para resaltar las diferencias.

El siguiente script SQLPlus genera la definición del esquema en orden alfabético, para permitir la comparación. Hay dos secciones. La primera sección enumera cada columna, en el formato:

table_name.column_name: data_type = data_default <nullable>

La segunda sección enumera índices y restricciones, de la siguiente manera:

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)

El script sirve como referencia útil para extraer algunos de los detalles del esquema de Oracle. Este puede ser un buen conocimiento cuando se encuentra en los sitios de los clientes y no tiene las herramientas habituales disponibles, o cuando las políticas de seguridad le impiden acceder a la base de datos del sitio del cliente directamente desde su propia 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;
/

Lamentablemente, existen algunas limitaciones:

  1. Los retornos de carro y los espacios en blanco incorporados en data_defaults y las definiciones de restricciones de verificación pueden resaltarse como diferencias, aunque no tengan ningún efecto en el esquema.
  2. No incluye claves alternativas, índices únicos o índices de rendimiento. Esto requeriría una tercera instrucción SELECT en el script, haciendo referencia a las vistas de catálogo all_ind_columns y all_indexes.
  3. No incluye detalles de seguridad, sinónimos, paquetes, disparadores, etc. Los paquetes y disparadores se compararían mejor con un enfoque similar al que usted propuso originalmente. Se podrían agregar otros aspectos de la definición del esquema al script anterior.
  4. Las definiciones de FK anteriores identifican las columnas de clave externa de referencia, pero no la PK o la tabla a la que se hace referencia. Solo un detalle más que nunca llegué a hacer.

Incluso si no usa el script. Hay un cierto placer tecnológico en jugar con estas cosas.;-)

Mateo