Vì vậy, vấn đề là, phải có một người dùng ở trên cùng của hệ thống phân cấp, một người dùng không có người quản lý (trong ví dụ của bạn là người chỉnh sửa). Đó là lý do tại sao giải pháp cổ điển cho loại cấu trúc này là cho phép các giá trị null. Bạn thừa nhận điều này trong đoạn kết của mình:
Người khởi xướng là, nếu người dùng đầu tiên không có NGƯỜI SÁNG TẠO hoặc NGƯỜI CHỈNH SỬA thì không có "tạm thời":bạn phải loại bỏ ràng buộc bắt buộc. Nếu bạn làm điều này, vấn đề với ràng buộc khóa ngoại đệ quy sẽ biến mất.
Giải pháp thay thế là giới thiệu cái mà Aristotle gọi là Người di chuyển chính, Người dùng mà chính Người tạo ra nó. Cho bảng này:
create table t72
( userid number not null
, creator number not null
, editor number not null
, constraint t72_pk primary key (userid)
, constraint t72_cr_fk foreign key (creator)
references t72 (userid)
, constraint t72_ed_fk foreign key (editor)
references t72 (userid)
)
/
khá đơn giản để tạo một người dùng như vậy:
SQL> insert into t72 values (1,1,1)
2 /
1 row created.
SQL> commit;
Commit complete.
SQL>
Vậy tại sao đây không phải là giải pháp kinh điển. Chà, nó dẫn đến một mô hình dữ liệu hơi kỳ quặc có thể tạo ra sự tàn phá với các truy vấn phân cấp khi chúng tôi thêm một vài người dùng nữa.
SQL> select lpad(' ', level-1)|| u.userid as userid
2 , u.name
3 , u.editor
4 from t72 u
5 connect by
6 prior userid = editor
7 start with userid=1
8 /
ERROR:
ORA-01436: CONNECT BY loop in user data
no rows selected
SQL>
Về cơ bản, cơ sở dữ liệu không thích USERID là trình soạn thảo của riêng nó. Tuy nhiên, có một cách giải quyết, đó là NOCYCLE
từ khóa (giới thiệu với 10g). Điều này yêu cầu cơ sở dữ liệu bỏ qua các tham chiếu vòng tròn trong hệ thống phân cấp:
SQL> select lpad(' ', level-1)|| u.userid as userid
2 , u.name
3 , u.editor
4 from t72 u
5 connect by nocycle
6 prior userid = editor
7 start with userid=1
8 /
USERID NAME EDITOR
---------- ---------- ----------
1 ONE 1
2 TWO 1
3 THREE 2
4 FOUR 2
5 FIVE 2
6 SIX 2
7 SEVEN 6
7 rows selected.
SQL>
Ở đây không quan trọng vì dữ liệu vẫn được phân cấp chính xác. Nhưng điều gì sẽ xảy ra nếu chúng ta làm điều này:
SQL> update t72 set editor = 7
2 where userid = 1
3 /
1 row updated.
SQL>
Chúng ta mất một mối quan hệ (1 -> 7). Chúng tôi có thể sử dụng cột giả CONNECT_BY_ISNOCYCLE để xem hàng nào đang xoay vòng.
SQL> select lpad(' ', level-1)|| u.userid as userid
2 , u.name
3 , u.editor
4 , connect_by_iscycle
5 from t72 u
6 connect by nocycle
7 prior userid = editor
8 start with userid=1
9 /
USERID NAME EDITOR CONNECT_BY_ISCYCLE
---------- ---------- ---------- ------------------
1 ONE 7 0
2 TWO 1 0
3 THREE 2 0
4 FOUR 2 0
5 FIVE 2 0
6 SIX 2 0
7 SEVEN 6 1
7 rows selected.
SQL>
Oracle có nhiều chức năng bổ sung để làm việc với dữ liệu phân cấp trong SQL thuần túy dễ dàng hơn. Tất cả đều có trong tài liệu. Tìm hiểu thêm .