Så problemet er, at der skal være en bruger øverst i hierarkiet, en bruger for hvem der ikke er nogen manager (redaktør i dit eksempel). Derfor er den klassiske løsning på denne form for struktur at tillade nulværdier. Du anerkender dette i dit afsluttende afsnit:
Kickeren er, hvis den første bruger ikke har en CREATOR eller en EDITOR, så er der ingen "midlertidig":du skal droppe den obligatoriske begrænsning. Hvis du gør dette, vil problemet med den rekursive fremmednøgle-begrænsning forsvinde.
Alternativet er at introducere det, som Aristoteles kaldte en Prim-mover, en Bruger, hvis Skaber er sig selv. Givet denne tabel:
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)
)
/
det er ret nemt at oprette sådan en bruger:
SQL> insert into t72 values (1,1,1)
2 /
1 row created.
SQL> commit;
Commit complete.
SQL>
Så hvorfor er dette ikke den kanoniske løsning. Nå, det fører til en lidt skør datamodel, som kan skabe kaos med hierarkiske forespørgsler, når vi tilføjer et par flere brugere.
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>
Grundlæggende kan databasen ikke lide, at USERID er sin egen editor. Der er dog en løsning, som er NOCYCLE
søgeord (introduceret med 10g). Dette fortæller databasen at ignorere cirkulære referencer i hierarkiet:
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>
Her er det ligegyldigt, fordi dataene stadig er korrekt hierarkiske. Men hvad sker der, hvis vi gør dette:
SQL> update t72 set editor = 7
2 where userid = 1
3 /
1 row updated.
SQL>
Vi mister et forhold ( 1 -> 7). Vi kan bruge CONNECT_BY_ISNOCYCLE pseudo-kolonnen til at se, hvilken række der cykler.
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 har masser af ekstra funktionalitet, der gør det nemmere at arbejde med hierarkiske data i ren SQL. Det hele står i dokumentationen. Få mere at vide .