web-dev-qa-db-ja.com

MySQL-条件付き外部キー制約

アプリに次のcommentsテーブルがあります。

comments
--------
id           INT
foreign_id   INT
model        TEXT
comment_text TEXT
...

このテーブルのアイデアは、アプリのさまざまな部分のコメントを保存することです。つまり、ブログ投稿のコメントを保存できます。

1|34|blogpost|lorem ipsum...

ユーザー画像:

2|12|picture|lorem ipsum...

等々。

今、そのようなデータにFOREIGN KEY制約を強制する方法はありますか?

つまり、コメントテーブルで次のようになります。

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`)
-- but only when model='blogpost'
58
grzes

Polymorphic Associationsと呼ばれるデザインを実行しようとしています。つまり、外部キーは、いくつかの関連するテーブルのいずれかの行を参照できます。

ただし、外部キー制約は正確に1つのテーブルを参照する必要があります。 Commentsテーブルの別の列の値に応じて異なるテーブルを参照する外部キーを宣言することはできません。これは、リレーショナルデータベース設計のいくつかのルールに違反します。

より良い解決策は、コメントで参照される一種の「スーパーテーブル」を作成することです。

CREATE TABLE Commentable (
  id SERIAL PRIMARY KEY
);

CREATE TABLE Comments (
  comment_id SERIAL PRIMARY KEY,
  foreign_id INT NOT NULL,
  ...
  FOREIGN KEY (foreign_id) REFERENCES Commentable(id)
);

各コンテンツタイプは、このスーパーテーブルのサブタイプと見なされます。これはinterfaceのオブジェクト指向の概念に似ています。

CREATE TABLE BlogPosts (
  blogpost_id INT PRIMARY KEY, -- notice this is not auto-generated
  ...
  FOREIGN KEY (blogpost_id) REFERENCES Commentable(id)
);

CREATE TABLE UserPictures (
  userpicture_id INT PRIMARY KEY, -- notice this is not auto-generated
  ...
  FOREIGN KEY (userpicture_id) REFERENCES Commentable(id)
);

BlogPostsまたはUserPicturesに行を挿入する前に、Commentableに新しい行を挿入して、新しい疑似キーIDを生成する必要があります。次に、コンテンツをそれぞれのサブタイプテーブルに挿入するときに、生成されたIDを使用できます。

これらすべてを実行したら、参照整合性制約に依存できます。

89
Bill Karwin