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:
auftable_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:
- 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.
- 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.
- 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.
- 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