Một công cụ so sánh lược đồ là một ý tưởng hay. Lược đồ cơ sở dữ liệu phức tạp hơn nhiều so với hầu hết mọi người cho rằng, và mọi sự khác biệt giữa hai lược đồ cơ sở dữ liệu đều có khả năng gây ra lỗi.
Nếu bạn vẫn muốn tự mình làm điều đó, thì cách tốt nhất mà tôi đã tìm thấy là trích xuất các định nghĩa lược đồ thành văn bản, sau đó chạy so sánh văn bản. Miễn là mọi thứ được sắp xếp theo thứ tự bảng chữ cái, sau đó bạn có thể sử dụng tính năng So sánh tài liệu trong Microsoft Word (hoặc FC.EXE, DIFF hoặc tương đương) để làm nổi bật sự khác biệt.
Tập lệnh SQLPlus sau xuất định nghĩa lược đồ theo thứ tự bảng chữ cái, để cho phép so sánh. Có hai phần. Phần đầu tiên liệt kê từng cột, ở định dạng:
table_name.column_name: data_type = data_default <nullable>
Phần thứ hai liệt kê các chỉ mục và ràng buộc, như sau:
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)
Tập lệnh đóng vai trò là một tham chiếu hữu ích để trích xuất một số chi tiết của lược đồ Oracle. Đây có thể là kiến thức tốt cần có khi bạn ra ngoài tại các trang web khách hàng và bạn không có sẵn các công cụ thông thường hoặc khi các chính sách bảo mật ngăn bạn truy cập cơ sở dữ liệu trang web khách hàng trực tiếp từ PC của riêng bạn.
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;
/
Thật không may, có một số hạn chế:
- Các dấu xuống dòng được nhúng và khoảng trắng trong data_defaults và kiểm tra các định nghĩa ràng buộc, có thể được đánh dấu là sự khác biệt, mặc dù chúng không ảnh hưởng đến lược đồ.
- Không bao gồm các khóa thay thế, chỉ mục duy nhất hoặc chỉ mục hiệu suất. Điều này sẽ yêu cầu câu lệnh SELECT thứ ba trong tập lệnh, tham chiếu đến all_ind_columns và all_indexes catalogue.
- Không bao gồm chi tiết bảo mật, từ đồng nghĩa, gói, trình kích hoạt, v.v. Các gói và trình kích hoạt sẽ được so sánh tốt nhất bằng cách sử dụng cách tiếp cận tương tự như cách bạn đề xuất ban đầu. Các khía cạnh khác của định nghĩa giản đồ có thể được thêm vào tập lệnh trên.
- Các định nghĩa FK ở trên xác định các cột khóa ngoại tham chiếu, nhưng không xác định PK hoặc bảng đang được tham chiếu. Chỉ một chi tiết nữa mà tôi chưa bao giờ làm.
Ngay cả khi bạn không sử dụng script. Có một niềm vui nhất định về công nghệ khi chơi với thứ này.;-)
Matthew