【问题标题】:MySQL database normalization and best practiceMySQL 数据库规范化和最佳实践
【发布时间】:2018-04-03 01:15:05
【问题描述】:

我有两张桌子:

CREATE TABLE `ch_nav_items_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `menu_id` int(11) DEFAULT NULL,
  `parent` int(4) DEFAULT NULL,
  `displayname` varchar(60) CHARACTER SET latin1 DEFAULT NULL,
  `link` varchar(60) CHARACTER SET latin1 DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `link` (`link`)
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8

CREATE TABLE `ch_houses_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `displayname` varchar(30) DEFAULT NULL,
  `alias` varchar(30) DEFAULT NULL,
  `street` varchar(100) DEFAULT '',
  `zip` int(5) DEFAULT NULL,
  `city` varchar(100) DEFAULT NULL,
  `active` tinyint(1) DEFAULT NULL,
  `alias_link` varchar(60) CHARACTER SET latin1 DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `alias_link` (`alias_link`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8

我想标准化。

在 ch_nav_items_test 我存储了网站的所有导航链接。 menu_id 用于区分前端、后端、页脚...导航。 父级是建立多级导航。房屋链接将位于第二层。

当我创建一个新房子时,它会有一个显示名称(例如 House Magic)和一个自动创建的别名(例如 house-magic)。这个别名也是链接,前缀为“houses/”(例如,houses/house-magic 将是 ch_nav_items_test 中的链接)。显示名称存储在两个表 atm 但恕我直言我不能使用外键,因为导航项目表不仅有房屋链接,因此房屋表中不存在值。我无法构建这个外键。

我的结尾是:

  • ch_nav_items_test.displayname = "House Magic"
  • ch_nav_itmes_test.link = "houses/house-magic"
  • ch_houses_test.displayname = "House Magic"
  • ch_houses_test.alias = "house-magic"
  • ch_houses_test.alias-link = "houses/house-magic"

我临时创建的 ch_houses_test.alias-link 尝试使用外键链接到导航链接列但没有成功。

如果有外链就好了,因为当我删除房子时,我也需要删除相关的导航项链接。 另外,如果我更改了房子的名称,导航项中的链接也需要更改。别名也是如此。

Atm 我被困在如何规范化这个问题上,我不知道这里的最佳做法是什么。 我可以完全重新定义我的表结构,但我想保持它非常简单。

我知道我可以在 php 代码中处理所有这些,这是我通常会做的,因为我更像是 php 编码器而不是 mysql 专家,但是如果有一种简单的方法可以用很少的查询来处理大部分问题,我更喜欢这个。

【问题讨论】:

  • 你需要这方面的教程。您还需要了解实体关系的概念。

标签: php mysql database normalization


【解决方案1】:

这个问题在OOP中可以类比来描述。如果您需要多个类来具有相同的属性或行为。你会怎么做?您创建一个接口来对这些类进行分组。

现在回到您的示例,nav_itemhouse 和其他表的公共属性。你需要的是一个父表或者nav_item表可以引用的接口。让我们将此表称为links 并像这样定义它

CREATE TABLE `links` (
  `id` varchar(60) NOT NULL CHARACTER SET latin1,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

那么houses表和其他表可以创建自己的链接并引用

CREATE TABLE `ch_houses_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  ...
  `link` varchar(60) NOT NULL CHARACTER SET latin1,
  PRIMARY KEY (`id`),
  CONSTRAINT FOREIGN KEY (`link`) REFERENCES `links` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8

最后,nav_item 也可以引用属于house 或其他实体的链接

CREATE TABLE `ch_nav_items_test` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `menu_id` int(11) DEFAULT NULL,
  `parent` int(4) DEFAULT NULL,
  `displayname` varchar(60) CHARACTER SET latin1 DEFAULT NULL,
  `link` varchar(60) CHARACTER SET latin1 DEFAULT NULL,
  PRIMARY KEY (`id`),
  CONSTRAINT FOREIGN KEY (`link`) REFERENCES `links` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8

当您想同时删除或更新 house 和 nav_item 链接时,只需删除或更新它们在links 表中的对应记录即可。如果您想将nav_item 扩展到其他实体,只需将这些实体引用到links 表即可。

【讨论】:

  • 我喜欢这个主意。也就是说,当我创建一个新房子时,我需要先创建一个链接行,对吧?因为如果没有,我无法创建房子,因为没有与新链接名称相关的外键,对吧?
  • 这个假设,房子链接总是唯一的,因为当我需要删除房子时,我不能通过 ID 删除它,我需要通过另一个表中的链接删除它
  • 是的,没错。另一种方法是为house 和其他实体创建一个父类。父类有 id 字段,house 可以用作它的 id 和链接字段以在nav_item 中使用。所以你可以使用id删除父类,housenav_item也会被删除。
猜你喜欢
  • 2021-07-15
  • 2011-10-31
  • 1970-01-01
  • 2011-12-30
  • 2013-10-30
  • 2013-06-30
  • 2011-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多