Така че проблемът е, че трябва да има потребител на върха на йерархията, потребител, за когото няма мениджър (редактор във вашия пример). Ето защо класическото решение за този вид структура е да се разрешат нулеви стойности. Вие потвърждавате това в заключителния си параграф:
Най-важното е, че ако първият потребител няма СЪЗДАТЕЛ или РЕДАКТОР, тогава няма "временно":трябва да се откажете от задължителното ограничение. Ако направите това, проблемът с ограничението на рекурсивния външен ключ ще изчезне.
Алтернативата е да се въведе това, което Аристотел нарича Първичен двигател, потребител, чийто Създател е самият той. При тази таблица:
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. Всичко е в документацията. Научете повече .