sql >> Base de Datos >  >> RDS >> Oracle

Modelo de rieles con clave externa a sí mismo

Entonces, el problema es que tiene que haber un usuario en la parte superior de la jerarquía, un usuario para el que no haya administrador (editor en su ejemplo). Es por eso que la solución clásica a este tipo de estructura es permitir valores nulos. Usted reconoce esto en su párrafo de cierre:

El truco es que si el primer usuario no tiene un CREADOR o un EDITOR, entonces no hay "temporal":debe deshacerse de la restricción obligatoria. Si hace esto, el problema con la restricción de clave foránea recursiva desaparecerá.

La alternativa es introducir lo que Aristóteles llamó un Primer Motor, un Usuario cuyo Creador es él mismo. Dada esta tabla:

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

es bastante simple crear un usuario así:

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

1 row created.

SQL> commit;

Commit complete.

SQL>

Entonces, ¿por qué no es esta la solución canónica? Bueno, conduce a un modelo de datos un poco extraño que puede causar estragos en las consultas jerárquicas una vez que agregamos algunos usuarios más.

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> 

Básicamente, a la base de datos no le gusta que USERID sea su propio editor. Sin embargo, hay una solución, que es el NOCYCLE palabra clave (introducida con 10g). Esto le dice a la base de datos que ignore las referencias circulares en la jerarquía:

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>

Aquí no importa porque los datos siguen estando correctamente jerarquizados. Pero que pasa si hacemos esto:

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

1 row updated.

SQL> 

Perdemos una relación (1 -> 7). Podemos usar la pseudocolumna CONNECT_BY_ISNOCYCLE para ver qué fila está ciclando.

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 tiene muchas funciones adicionales para facilitar el trabajo con datos jerárquicos en SQL puro. Está todo en la documentación. Más información .