Хорошая идея - инструмент сравнения схем. Схема базы данных гораздо сложнее, чем думает большинство людей, и любая разница между двумя схемами базы данных может привести к ошибкам.
Если вы все еще хотите сделать это самостоятельно, лучший способ, который я нашел, состоит в том, чтобы извлечь определения схемы в текст, а затем выполнить сравнение текста. Пока все отсортировано по алфавиту, вы можете использовать функцию сравнения документов в Microsoft Word (или FC.EXE, DIFF или эквивалентную), чтобы выделить различия.
Следующий скрипт SQLPlus выводит определение схемы в алфавитном порядке, чтобы разрешить сравнение. Есть два раздела. В первом разделе перечислены все столбцы в формате:
table_name.column_name: data_type = data_default <nullable>
Во втором разделе перечислены индексы и ограничения следующим образом:
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)
Сценарий служит полезной ссылкой для извлечения некоторых деталей схемы Oracle. Это может быть полезно, когда вы находитесь на клиентских сайтах и у вас нет обычных инструментов, или когда политики безопасности не позволяют вам получить доступ к базе данных клиентского сайта напрямую с вашего компьютера.
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;
/
К сожалению, есть несколько ограничений:
- Встроенные возвраты каретки и пробелы в data_defaults, а также проверки определений ограничений могут быть выделены как различия, даже если они не влияют на схему.
- Не включает альтернативные ключи, уникальные индексы или индексы производительности. Для этого потребуется третий оператор SELECT в сценарии, ссылающийся на представления каталога all_ind_columns и all_indexes.
- Не включает сведения о безопасности, синонимы, пакеты, триггеры и т. Д. Пакеты и триггеры лучше всего сравнивать, используя подход, аналогичный тому, который вы первоначально предложили. Другие аспекты определения схемы могут быть добавлены к приведенному выше сценарию.
- Приведенные выше определения FK идентифицируют ссылающиеся столбцы внешнего ключа, но не PK или таблицу, на которую ссылаются. Еще одна деталь, которую я так и не нашел.
Даже если вы не используете сценарий. Есть определенное техническое удовольствие от игры с этим материалом. ; -)
Мэтью