Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Rails-Modell mit Fremdschlüssel für sich selbst

Das Problem ist also, dass es einen Benutzer an der Spitze der Hierarchie geben muss, einen Benutzer, für den es keinen Manager gibt (in Ihrem Beispiel den Editor). Aus diesem Grund besteht die klassische Lösung für diese Art von Struktur darin, Nullwerte zuzulassen. Sie erkennen dies in Ihrem Schlussabsatz an:

Der Kicker ist, wenn der erste Benutzer keinen CREATOR oder EDITOR hat, dann gibt es kein "temporär":Sie müssen die obligatorische Einschränkung aufgeben. Wenn Sie dies tun, wird das Problem mit der rekursiven Fremdschlüsselbeschränkung verschwinden.

Die Alternative besteht darin, das einzuführen, was Aristoteles einen Prime Mover nannte, einen Benutzer, dessen Schöpfer er selbst ist. Angesichts dieser Tabelle:

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 ist ziemlich einfach, einen solchen Benutzer zu erstellen:

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

1 row created.

SQL> commit;

Commit complete.

SQL>

Warum ist das nicht die kanonische Lösung? Nun, es führt zu einem etwas verrückten Datenmodell, das mit hierarchischen Abfragen Chaos anrichten kann, sobald wir ein paar weitere Benutzer hinzufügen.

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> 

Grundsätzlich mag es die Datenbank nicht, dass USERID ihr eigener Editor ist. Es gibt jedoch eine Problemumgehung, nämlich NOCYCLE Schlüsselwort (eingeführt mit 10g). Dies weist die Datenbank an, Zirkelverweise in der Hierarchie zu ignorieren:

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>

Hier spielt es keine Rolle, da die Daten immer noch korrekt hierarchisch sind. Aber was passiert, wenn wir Folgendes tun:

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

1 row updated.

SQL> 

Wir verlieren eine Beziehung (1 -> 7). Wir können die Pseudospalte CONNECT_BY_ISNOCYCLE verwenden, um zu sehen, welche Zeile zyklisch ist.

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 verfügt über viele zusätzliche Funktionen, die die Arbeit mit hierarchischen Daten in reinem SQL erleichtern. Das steht alles in der Dokumentation. Erfahren Sie mehr .