Oracle
 sql >> Database >  >> RDS >> Oracle

Modello di rotaie con chiave esterna su se stesso

Quindi il problema è che ci deve essere un utente in cima alla gerarchia, un utente per il quale non esiste un manager (editor nel tuo esempio). Ecco perché la soluzione classica a questo tipo di struttura è consentire valori nulli. Lo riconosci nel paragrafo di chiusura:

Il kicker è che se il primo utente non ha un CREATOR o un EDITOR allora non c'è "temporaneo":devi abbandonare il vincolo obbligatorio. Se si esegue questa operazione, il problema con il vincolo di chiave esterna ricorsiva scomparirà.

L'alternativa è introdurre quello che Aristotele chiamava un Primo Motore, un Utente il cui Creatore è se stesso. Data questa tabella:

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)
)
/

è abbastanza semplice creare un utente del genere:

SQL> insert into t72 values (1,1,1)
  2  /

1 row created.

SQL> commit;

Commit complete.

SQL>

Allora perché non è questa la soluzione canonica. Bene, porta a un modello di dati leggermente stravagante che può creare scompiglio con le query gerarchiche una volta che aggiungiamo qualche altro utente.

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> 

Fondamentalmente al database non piace che USERID sia il proprio editor. Tuttavia, esiste una soluzione alternativa, che è il NOCYCLE parola chiave (introdotta con 10g). Questo dice al database di ignorare i riferimenti circolari nella gerarchia:

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>

Qui non importa perché i dati sono ancora correttamente gerarchici. Ma cosa succede se facciamo questo:

SQL> update t72 set editor = 7
  2  where userid = 1
  3  /

1 row updated.

SQL> 

Perdiamo una relazione ( 1 -> 7). Possiamo usare la pseudo-colonna CONNECT_BY_ISNOCYCLE per vedere quale riga sta scorrendo.

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 ha molte funzionalità aggiuntive per semplificare il lavoro con i dati gerarchici in puro SQL. È tutto nella documentazione. Scopri di più .