MySQL - условные ограничения внешнего ключа - PullRequest
55 голосов
/ 05 января 2010

В моем приложении есть следующая таблица комментариев:

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'

1 Ответ

87 голосов
/ 05 января 2010

Вы пытаетесь создать дизайн, который называется Полиморфная ассоциация . То есть внешний ключ может ссылаться на строки в любой из нескольких связанных таблиц.

Но ограничение внешнего ключа должно ссылаться ровно на одну таблицу. Вы не можете объявить внешний ключ, который ссылается на разные таблицы, в зависимости от значения в другом столбце вашей таблицы 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)
);

Каждый из ваших типов контента будет считаться подтипом этого супертаблицы. Это аналогично объектно-ориентированной концепции интерфейса .

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, чтобы сгенерировать новый идентификатор псевдоключа. Затем вы можете использовать этот сгенерированный идентификатор при вставке содержимого в соответствующую таблицу подтипов.

Как только вы все это сделаете, вы можете положиться на ограничения ссылочной целостности.

...