Então o problema é que tem que haver um usuário no topo da hierarquia, um usuário para quem não há gerente (editor no seu exemplo). É por isso que a solução clássica para esse tipo de estrutura é permitir valores nulos. Você reconhece isso em seu parágrafo de encerramento:
O kicker é, se o primeiro usuário não tiver um CRIADOR ou um EDITOR, então não há "temporário":você tem que abandonar a restrição obrigatória. Se você fizer isso, o problema com a restrição de chave estrangeira recursiva desaparecerá.
A alternativa é introduzir o que Aristóteles chamou de Primeiro Motor, um Usuário cujo Criador é ele mesmo. Dada esta tabela:
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)
)
/
é bem simples criar um usuário assim:
SQL> insert into t72 values (1,1,1)
2 /
1 row created.
SQL> commit;
Commit complete.
SQL>
Então, por que essa não é a solução canônica. Bem, isso leva a um modelo de dados um pouco maluco que pode criar estragos com consultas hierárquicas quando adicionamos mais alguns usuários.
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>
Basicamente, o banco de dados não gosta que USERID seja seu próprio editor. No entanto, existe uma solução alternativa, que é o
NOCYCLE
palavra-chave (introduzida com 10g). Isso diz ao banco de dados para ignorar referências circulares na hierarquia: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>
Aqui não importa porque os dados ainda são corretamente hierárquicos. Mas o que acontece se fizermos isso:
SQL> update t72 set editor = 7
2 where userid = 1
3 /
1 row updated.
SQL>
Perdemos um relacionamento ( 1 -> 7). Podemos usar a pseudo-coluna CONNECT_BY_ISNOCYCLE para ver qual linha está circulando.
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>
O Oracle tem muitas funcionalidades adicionais para facilitar o trabalho com dados hierárquicos em SQL puro. Está tudo na documentação. Saiba mais .