sql >> データベース >  >> RDS >> Oracle

それ自体への外部キーを持つRailsモデル

    したがって、問題は、階層の最上位にユーザー、つまりマネージャーがいないユーザー(この例ではエディター)が存在する必要があるということです。そのため、この種の構造に対する古典的な解決策は、null値を許可することです。あなたは最後の段落でこれを認めます:

    キッカーは、最初のユーザーがCREATORまたはEDITORを持っていない場合、「一時的な」ものはありません。必須の制約を破棄する必要があります。これを行うと、再帰的な外部キー制約の問題が解消されます。

    別の方法は、アリストテレスが原動機と呼んだものを紹介することです。これは、作成者が自分自身であるユーザーです。この表を考えると:

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

    このようなユーザーを作成するのは非常に簡単です:

    SQL> insert into t72 values (1,1,1)
      2  /
    
    1 row created.
    
    SQL> commit;
    
    Commit complete.
    
    SQL>
    

    では、なぜこれが標準的な解決策ではないのでしょうか。少し風変わりなデータモデルになり、ユーザーを数人追加すると、階層クエリで大混乱を引き起こす可能性があります。

    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> 
    

    基本的に、データベースはUSERIDが独自のエディターであることを好みません。ただし、回避策があります。それはNOCYCLEです。 キーワード(10gで導入)。これにより、データベースは階層内の循環参照を無視するようになります。

    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>
    

    ここでは、データがまだ正しく階層化されているため、問題ではありません。しかし、これを行うとどうなりますか:

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

    私たちは関係を失います(1-> 7)。 CONNECT_BY_ISNOCYCLE疑似列を使用して、どの行が循環しているかを確認できます。

    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には、純粋なSQLで階層データを簡単に操作できるようにするための多くの追加機能があります。それはすべてドキュメントにあります。 詳細



    1. 行のNULLの数を数える

    2. Oracle PL/SQLリリース12.2.0.1.0と12.1.0.2.0-パラメータを使用して即時実行

    3. Openshiftとnet-sshの非互換性? (2.9.3-beta1 vs 2.9.2)

    4. PostgreSQLでデータベースの作成日を取得する