Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Vergleichen Sie zwei Schemas und aktualisieren Sie das alte Schema mit den neuen Spalten des neuen Schemas

Ein Schemavergleichstool ist eine gute Idee. Das Datenbankschema ist viel komplizierter, als die meisten glauben, und jeder Unterschied zwischen zwei Datenbankschemata kann Fehler verursachen.

Wenn Sie es immer noch selbst tun möchten, ist der beste Ansatz, den ich gefunden habe, die Schemadefinitionen in Text zu extrahieren und dann einen Textvergleich durchzuführen. Solange alles alphabetisch sortiert ist, können Sie die Funktion zum Vergleichen von Dokumenten in Microsoft Word (oder FC.EXE, DIFF oder gleichwertig) verwenden, um die Unterschiede hervorzuheben.

Das folgende SQLPlus-Skript gibt die Schemadefinition alphabetisch aus, um einen Vergleich zu ermöglichen. Es gibt zwei Abschnitte. Der erste Abschnitt listet jede Spalte im Format:

auf
table_name.column_name: data_type = data_default <nullable>

Der zweite Abschnitt listet Indizes und Einschränkungen wie folgt auf:

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)

Das Skript dient als nützliche Referenz zum Extrahieren einiger Details des Oracle-Schemas. Dies kann hilfreich sein, wenn Sie an Kundenstandorten unterwegs sind und Ihre üblichen Tools nicht zur Verfügung haben, oder wenn Sicherheitsrichtlinien Sie daran hindern, direkt von Ihrem eigenen PC aus auf eine Kundendatenbank zuzugreifen.

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;
/

Leider gibt es ein paar Einschränkungen:

  1. Eingebettete Wagenrückläufe und Leerzeichen in data_defaults und Check-Constraint-Definitionen können als Unterschiede hervorgehoben werden, obwohl sie keine Auswirkung auf das Schema haben.
  2. Umfasst keine alternativen Schlüssel, eindeutigen Indizes oder Leistungsindizes. Dies würde eine dritte SELECT-Anweisung im Skript erfordern, die auf die Katalogansichten all_ind_columns und all_indexes verweist.
  3. Enthält keine Sicherheitsdetails, Synonyme, Pakete, Auslöser usw. Pakete und Auslöser lassen sich am besten mit einem Ansatz vergleichen, der dem von Ihnen ursprünglich vorgeschlagenen ähnelt. Andere Aspekte der Schemadefinition könnten dem obigen Skript hinzugefügt werden.
  4. Die obigen FK-Definitionen identifizieren die referenzierenden Fremdschlüsselspalten, aber nicht den PK oder die referenzierte Tabelle. Nur noch ein Detail, zu dem ich nie gekommen bin.

Auch wenn Sie das Skript nicht verwenden. Es gibt ein gewisses technisches Vergnügen, mit diesem Zeug zu spielen.;-)

Matthäus