Alat perbandingan skema adalah ide yang bagus. Skema database jauh lebih rumit daripada yang diberikan kebanyakan orang, dan setiap perbedaan antara dua skema database berpotensi menyebabkan bug.
Jika Anda masih ingin melakukannya sendiri, pendekatan terbaik yang saya temukan adalah mengekstrak definisi skema ke teks, lalu menjalankan perbandingan teks. Selama semuanya diurutkan berdasarkan abjad, Anda kemudian dapat menggunakan fitur Bandingkan Dokumen di Microsoft Word (atau FC.EXE, DIFF atau yang setara), untuk menyoroti perbedaannya.
Skrip SQLPlus berikut mengeluarkan definisi skema menurut abjad, untuk memungkinkan perbandingan. Ada dua bagian. Bagian pertama mencantumkan setiap kolom, dalam format:
table_name.column_name: data_type = data_default <nullable>
Bagian kedua mencantumkan indeks dan batasan, sebagai berikut:
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)
Script berfungsi sebagai referensi yang berguna untuk mengekstrak beberapa detail skema Oracle. Ini bisa menjadi pengetahuan yang baik untuk dimiliki ketika Anda berada di luar situs klien dan Anda tidak memiliki alat yang biasa tersedia, atau ketika kebijakan keamanan mencegah Anda mengakses database situs klien langsung dari PC Anda sendiri.
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;
/
Sayangnya, ada beberapa batasan:
- Kembali carriage yang disematkan dan spasi kosong di data_defaults, dan periksa definisi batasan, dapat disorot sebagai perbedaan, meskipun tidak ada pengaruhnya pada skema.
- Tidak termasuk kunci alternatif, indeks unik, atau indeks kinerja. Ini akan membutuhkan pernyataan SELECT ketiga dalam skrip, yang merujuk tampilan katalog all_ind_columns dan all_indexes.
- Tidak termasuk detail keamanan, sinonim, paket, pemicu, dll. Paket dan pemicu akan lebih baik dibandingkan menggunakan pendekatan yang serupa dengan yang Anda usulkan sebelumnya. Aspek lain dari definisi skema dapat ditambahkan ke skrip di atas.
- Definisi FK di atas mengidentifikasi kolom kunci asing yang merujuk, tetapi bukan PK atau tabel yang dirujuk. Hanya satu detail lagi yang tidak pernah saya lakukan.
Bahkan jika Anda tidak menggunakan skrip. Ada kesenangan teknisi tertentu dalam bermain dengan barang ini.;-)
Matius