Problém je tedy v tom, že na vrcholu hierarchie musí být uživatel, pro kterého neexistuje žádný správce (ve vašem příkladu editor). Proto klasickým řešením tohoto druhu struktury je povolit hodnoty null. Berete to na vědomí v závěrečném odstavci:
Hlavní je, že pokud první uživatel nemá Tvůrce nebo EDITORA, pak neexistuje žádné „dočasné“:musíte se vzdát povinného omezení. Pokud to uděláte, problém s rekurzivním omezením cizího klíče zmizí.
Alternativou je představit to, co Aristoteles nazval Prvotním hybatelem, Uživatelem, jehož Stvořitelem je on sám. Vzhledem k této tabulce:
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)
)
/
vytvořit takového uživatele je docela jednoduché:
SQL> insert into t72 values (1,1,1)
2 /
1 row created.
SQL> commit;
Commit complete.
SQL>
Proč to tedy není kanonické řešení. Vede to k trochu šílenému datovému modelu, který může způsobit chaos s hierarchickými dotazy, jakmile přidáme několik dalších uživatelů.
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>
Databáze se v zásadě nelíbí, že USERID je jejím vlastním editorem. Existuje však řešení, kterým je NOCYCLE
klíčové slovo (uvedeno s 10g). To říká databázi, aby ignorovala cyklické odkazy v hierarchii:
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>
Zde to nevadí, protože data jsou stále správně hierarchická. Ale co se stane, když uděláme toto:
SQL> update t72 set editor = 7
2 where userid = 1
3 /
1 row updated.
SQL>
Ztrácíme vztah (1 -> 7). Můžeme použít pseudosloupec CONNECT_BY_ISNOCYCLE, abychom viděli, který řádek se cykluje.
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 má spoustu dalších funkcí, které usnadňují práci s hierarchickými daty v čistém SQL. Vše je v dokumentaci. Zjistěte více .