MySQL - 条件外键约束

grz*_*zes 55 mysql sql database-design foreign-keys polymorphic-associations

我的应用程序中有以下"评论"表:

comments
--------
id           INT
foreign_id   INT
model        TEXT
comment_text TEXT
...
Run Code Online (Sandbox Code Playgroud)

这个表的想法是存储我的应用程序的各个部分的注释 - 它可以存储博客帖子的评论,即:

1|34|blogpost|lorem ipsum...
Run Code Online (Sandbox Code Playgroud)

用户图片:

2|12|picture|lorem ipsum...
Run Code Online (Sandbox Code Playgroud)

等等.

现在,有没有办法强制FOREIGN KEY约束这些数据?

即在评论表中这样的东西:

FOREIGN KEY (`foreign_id`) REFERENCES blogposts (`id`)
//but only when model='blogpost'
Run Code Online (Sandbox Code Playgroud)

Bil*_*win 91

您正在尝试进行称为多态关联的设计.也就是说,外键可以引用几个相关表中的任何一个中的行.

但是外键约束必须恰好引用一个表.您不能声明引用不同表的外键,具体取决于表的另一列中的值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)
);
Run Code Online (Sandbox Code Playgroud)

您的每种内容类型都将被视为此超类型的子类型.这类似于面向对象的接口概念.

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)
);
Run Code Online (Sandbox Code Playgroud)

在将行插入BlogPosts或之前UserPictures,必须插入新行Commentable以生成新的伪代码ID.然后,您可以在将内容插入相应的子类型表时使用该生成的ID.

完成所有操作后,您可以依赖参照完整性约束.

  • @MattMcCormick,我不再回答关于SO的问题了,因为讨厌的版主已经让它无法参与. (16认同)
  • 哦好的.感谢您过去的参与.我读了很多关于单表继承和多态关联的答案,还观看了你在其中一个中引用的演讲中的幻灯片.它帮助我更好地识别数据库中可能导致问题的情况.我已将您的书添加到我的阅读列表中,并可能会将其用于我的下一本软件阅读. (5认同)
  • __Polymorphic Associations__这个词给了我很多帮助. (5认同)
  • @BillKarwin 很高兴看到您上面的评论不再适用。 (3认同)
  • 我假设UserPictures包含一个引用User表的字段user_id.如何以删除将级联到Commentable表的方式处理用户删除?我在这里问了这个问题 - http://stackoverflow.com/questions/11497149/how-to-enforce-referential-integrity-on-single-table-inheritance-如果你能解释一下如何处理这个问题会很感激打嗝我被困住了. (2认同)