所以,問題是,必須有在層次結構頂部的用戶,用戶對他們來說,沒有經理(在你的例子編輯器)。這就是爲什麼這種結構的典型解決方案是允許空值。你在你的結束段落承認這一點:
「從理論上講,這是有道理的,所有 用戶(除第一)有 創作者和編輯,有什麼辦法 做到這一點,而不暫時 移除非空約束?」
踢球者是,如果第一個用戶沒有CREATOR或EDITOR那麼就沒有「臨時」:你必須拋棄強制約束。如果你這樣做,遞歸外鍵約束的問題將消失。
另一種方法是引入亞里士多德稱之爲Prime Mover的原創者自己的用戶。鑑於此表:
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)
)
/
它非常簡單,創建這樣一個用戶:
SQL> insert into t72 values (1,1,1)
2/
1 row created.
SQL> commit;
Commit complete.
SQL>
那麼,爲什麼這不就是典型的解決方案。那麼它會導致一個稍微古怪的數據模型,一旦我們添加了更多的用戶,就可能對分層查詢造成嚴重破壞。
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>
基本上數據庫不喜歡USERID爲自身的編輯器。但是,有一個解決方法,即NOCYCLE
關鍵字(與10g一起引入)。這告訴數據庫忽略層次結構中的循環引用:
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>
這裏沒關係,因爲數據仍然是正確的分層結構。但是,如果我們這樣做會發生什麼:
SQL> update t72 set editor = 7
2 where userid = 1
3/
1 row updated.
SQL>
我們失去了一種關係(1→7)。我們可以使用CONNECT_BY_ISNOCYCLE僞列,看看哪一行循環。
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擁有許多附加功能,可以更輕鬆地在純SQL中處理分層數據。這些都在文檔中。 Find out more。
這是雞和蛋的問題類型是這樣,使外鍵有點討厭的。大多數Rails應用程序不會將它們用於慣例之外,這會讓人頭痛不已,並且承認引用不一致的潛在風險。 – tadman 2011-04-05 05:00:14