Så problemet är att det måste finnas en användare överst i hierarkin, en användare för vilken det inte finns någon chef (redaktör i ditt exempel). Det är därför den klassiska lösningen på denna typ av struktur är att tillåta nollvärden. Du bekräftar detta i ditt avslutande stycke:
Kickern är, om den första användaren inte har en CREATOR eller en EDITOR så finns det ingen "tillfällig":du måste avstå från den obligatoriska begränsningen. Om du gör detta kommer problemet med den rekursiva främmande nyckeln att försvinna.
Alternativet är att introducera vad Aristoteles kallade en Prime Mover, en Användare vars Skapare är han själv. Med tanke på denna tabell:
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 är ganska enkelt att skapa en sådan användare:
SQL> insert into t72 values (1,1,1)
2 /
1 row created.
SQL> commit;
Commit complete.
SQL>
Så varför är inte detta den kanoniska lösningen. Det leder till en lite knäpp datamodell som kan skapa kaos med hierarkiska frågor när vi väl lägger till några fler användare.
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>
I grund och botten gillar databasen inte att USERID är sin egen redaktör. Det finns dock en lösning, som är NOCYCLE
nyckelord (infört med 10g). Detta säger åt databasen att ignorera cirkulära referenser i hierarkin:
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>
Här spelar det ingen roll eftersom uppgifterna fortfarande är korrekt hierarkiska. Men vad händer om vi gör det här:
SQL> update t72 set editor = 7
2 where userid = 1
3 /
1 row updated.
SQL>
Vi förlorar en relation ( 1 -> 7). Vi kan använda CONNECT_BY_ISNOCYCLE pseudo-kolumnen för att se vilken rad som cyklar.
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 massor av ytterligare funktioner för att göra det enklare att arbeta med hierarkisk data i ren SQL. Allt finns i dokumentationen. Ta reda på mer .