MySQL:规范化内容类型,类别和子类别

时间:2016-08-11 11:20:49

标签: mysql database-design database-normalization

我有以下基本表格结构

  • 内容

    • ID
    • type_id (FK to ContentType)
    • category_id (可为空的FK到类别)
    • sub_category_id (可为空的FK到SubCategory)
  • ContentType

    • ID
  • 分类

    • id
    • content_type_id (FK to ContentType)
  • 子类别

    • ID
    • category_id (FK到类别)

内容的类别应与其类型匹配非常重要。

同样,内容的子类别应与其类别相匹配。

我知道目前这对数据不匹配是敞开的。例如,内容记录可能具有其类型不允许的类别以及其类别不允许的子类别。

如何更改表格结构以防止此问题?或者我应该坚持使用应用程序逻辑?

按订单要求

CREATE TABLE `content_type` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   PRIMARY KEY (`id`)
)

CREATE TABLE `category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `content_type_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_category_content_type` FOREIGN KEY (`content_type_id`) REFERENCES `content_type` (`id`),
)

CREATE TABLE `sub_category` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_sub_category_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`),
)

CREATE TABLE `content` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `type_id` int(10) unsigned NOT NULL,
  `category_id` int(10) unsigned DEFAULT NULL,
  `sub_category_id` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_content_type` FOREIGN KEY (`type_id`) REFERENCES `content_type` (`id`),
  CONSTRAINT `fk_content_category` FOREIGN KEY (`category_id`) REFERENCES `category` (`id`)
  CONSTRAINT `fk_content_sub_category` FOREIGN KEY (`sub_category_id`) REFERENCES `sub_category` (`id`)
)

2 个答案:

答案 0 :(得分:1)

在MySQL中,您只能添加基本约束。你无法添加条件约束(很想看到它)。

或者,您可以在BEFORE INSERT / UPDATE TRIGGER中构建检查。并使用SIGNAL取消INSERT / UPDATE(请参阅https://dev.mysql.com/doc/refman/5.5/en/signal.html

TBH我认为如果你有第三方'它可能会成为真正的问题。系统直接向数据库说话。如果没有,您可以在您的应用程序中解决它。逻辑,并为第三方访问创建API。

如果你真的想在RDBMS级别解决这个问题,你可以看看PostgreSQL(通过CHECK)。

注意:关于您的类别表,我会考虑添加parent_id并将其保存在一个表中(自我关系)。这样就可以让你的类别通过第二级了。

答案 1 :(得分:1)

在Category表中,在(id,content_type_id)上创建唯一索引。在SubCategory表中,在(id,category_id)上创建唯一索引。

然后在Content表中,创建如下的FK:

constraint FK_ContentCategory foreign key( category_id, type_id )
    references Category( id, content_type_id )

constraint FK_ContentSubCategory foreign key( sub_category_id, category_id )
    references SubCategory( id, category_id )

Category和SubCategory表中的FK保持不变。

由于子类别取决于依赖于内容类型的类别,因此使FK引用反映相同的依赖链。现在,一旦在Content表中输入type_id,类别和子类别值必须属于正确的依赖链。

但是,如果您需要更改Content条目的类型,则必须先将category_id和sub_category_id更改为NULL,修改type_id,然后将正确的值插入category_id和sub_category_id。为稳固的数据完整性付出的代价很小。