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

SQLでは、2つのテーブルが相互に参照しても問題ありませんか?

    いいえ、大丈夫ではありません。テーブル間の循環参照は厄介です。この(10年前の)記事を参照してください: SQL By Design:The Circular Reference

    一部のDBMSはこれらを特別な注意を払って処理できますが、MySQLには問題があります。

    オプション1

    設計として、2つのFKの1つをnull許容にする。これにより、鶏と卵の問題を解決できます(最初にどのテーブルに挿入する必要がありますか?)。

    コードに問題があります。これにより、製品にデフォルトの画像を設定して、その画像が別の製品を参照できるようになります。

    このようなエラーを禁止するには、FK制約を次のようにする必要があります。

    CONSTRAINT FK_products_1 
      FOREIGN KEY (id, default_picture_id) 
      REFERENCES products_pictures (product_id, id)
      ON DELETE RESTRICT                            --- the SET NULL options would 
      ON UPDATE RESTRICT                            --- lead to other issues
    

    これにはUNIQUEが必要です テーブルproducts_picturesの制約/インデックス (product_id, id) 上記のFKが定義され、正しく機能するために。

    オプション2

    もう1つの方法は、Default_Picture_IDを削除することです。 productの列 テーブルを作成し、IsDefault BITを追加します pictureの列 テーブル。このソリューションの問題は、製品ごとに1つの画像のみがそのビットをオンにし、他のすべての画像がそれをオフにする方法です。 SQL-Server(およびPostgresでは)では、これは部分インデックスを使用して実行できます:

    CREATE UNIQUE INDEX is_DefaultPicture 
      ON products_pictures (Product_ID)
      WHERE IsDefault = 1 ;
    

    しかし、MySQLにはそのような機能はありません。

    オプション3

    このアプローチでは、両方のFK列をNOT NULLとして定義することもできます。 延期可能な制約を使用することです。これはPostgreSQLで機能し、Oracleでも機能すると思います。この質問と@Erwinによる回答を確認してください:SQLAlchemyの複雑な外部キー制約すべてのキー列がNULLではありません パート)。

    MySQLの制約は延期できません。

    オプション4

    (私が最もきれいだと思う)アプローチは、Default_Picture_IDを削除することです。 列を作成し、別のテーブルを追加します。 FK制約に循環パスはなく、すべてのFK列はNOT NULLになります このソリューションで:

    product_default_picture
    ----------------------
    product_id          NOT NULL
    default_picture_id  NOT NULL
    PRIMARY KEY (product_id)
    FOREIGN KEY (product_id, default_picture_id)
      REFERENCES products_pictures (product_id, id)
    

    これには、UNIQUEも必要です。 テーブルproducts_picturesの制約/インデックス (product_id, id) ソリューション1のように。

    要約すると、MySQLには2つのオプションがあります:

    • オプション1(null許容FK列)と上記の修正により、整合性を正しく適用します

    • オプション4(null許容FK列なし)



    1. OracleDG40DBCの微調整

    2. SQL、SELECTの使用方法

    3. ミリ秒単位の月ごとの値の合計

    4. YEAR()SQL Server(T-SQL)の例