我现在拥有的表是经过“硬编码”的,以使同一张表中的两个表之间具有关系,而该表具有两个外键。
在“关系”表之前:
CREATE TABLE IF NOT EXISTS `Item_To_Item` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`item1_id` INT(11) NOT NULL,
`item2_id` INT(11) NOT NULL,
`relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
`description` VARCHAR(1000) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_Item1_Id`
FOREIGN KEY (`item1_id`)
REFERENCES `Item` (`id`)
CONSTRAINT `fk_Item2_Id`
FOREIGN KEY (`item2_id`)
REFERENCES `Item` (`id`)
因此,在此之前,项目表上有两个多对一的引用来填充两个外键。
现在需要扩展此关系,使其在数据库中的表之间更通用(枚举,标签,功能等)。因此,现在,项可以与项相关,项可以与标签相关,标签可以与枚举关系值相关的标签等。
我对通用表的想法是添加一个类型表,以便可以标识每个项目,标签等,然后将关系表重构为类似这样的东西:
CREATE TABLE IF NOT EXISTS `Relationship` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`relater_id` INT(11) NOT NULL,
`relatee_id` INT(11) NOT NULL,
`relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
`description` VARCHAR(1000) NULL DEFAULT NULL,
`relater_type_id` INT(11) NULL,
`relatee_type_id` INT(11) NULL,
PRIMARY KEY (`id`),
INDEX `fk_Relatee_Id` (`relatee_id` ASC),
INDEX `fk_Relater_Id` (`relater_id` ASC),
CONSTRAINT `fk_Relater_Id`
FOREIGN KEY (`relater_id`)
CONSTRAINT `fk_Relatee_Id`
FOREIGN KEY (`relatee_id`)
因此,您现在可以确定type_id和表关联的项目类型,并且可以将其打开,以便任何两个表id都可以进入“关联”和“关联”外键列。
问题是我不知道如何使用外键进行这种概括。我相信他们只能引用一个表,所以我不确定如何使用通用键引用来做我想做的事情。此外,我可以看到双向关系存在的问题,其中A相互要求B,B相互要求A是冗余数据。我可以在应用程序中阻止这种冗余,但是我将不得不不断检查A到B的两侧||。从B到A。我想知道完成我想做的最好的方法。谢谢。
编辑:也许对我的基本类型(商品,功能,标签)有帮助吗?
编辑:我不认为答案像继承那样简单。至少从我所能知道的。我的问题是,无论类型如何,我都想关联两个常规项目。我不希望20列必须为null,因为它不是特定类型。我只希望能够将两个id以及两个type_ids传递给关系,以便可以关联任何两个对象。
答案 0 :(得分:1)
一种可能的解决方案是实现object_type和object_index表:
CREATE TABLE object_type (
`object_type_id` int(11) NOT NULL AUTO_INCREMENT,
`object_type` varchar(30) NOT NULL,
PRIMARY KEY (`object_type_id`),
UNIQUE (`object_type`));
CREATE TABLE object_index (
`object_id` int(11) NOT NULL AUTO_INCREMENT,
`object_type_id` int(11) NOT NULL,
PRIMARY KEY (`object_id`),
UNIQUE (`object_type_id`, `object_id`));
并仅定义与该表的关系。
CREATE TABLE IF NOT EXISTS `Relationship` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`relater_id` INT(11) NOT NULL,
`relatee_id` INT(11) NOT NULL,
`relationship` ENUM('requires', 'mutually_requires', 'required_by', 'relates', 'excludes') NULL DEFAULT NULL,
`description` VARCHAR(1000) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `fk_Relatee_Id` (`relatee_id` ASC),
INDEX `fk_Relater_Id` (`relater_id` ASC),
CONSTRAINT `fk_Relater_Id`
FOREIGN KEY (`relater_id`)
references object_index (`object_id`),
CONSTRAINT `fk_Relatee_Id`
FOREIGN KEY (`relatee_id`)
references object_index (`object_id`));
接下来,将定义每个对象表,使它们与唯一(object_type_id,object_id)元组上的object_index相关。在此示例中,每个表的默认值和检查约束的object_type_id应该是唯一的:
CREATE TABLE table1 (
`object_id` int(11) NOT NULL,
`object_type_id` int(11) NOT NULL DEFAULT 1 CHECK (object_type = 1),
`col1` varchar(4),
PRIMARY KEY (`object_id`),
CONSTRAINT fk_t1_ob_idx
FOREIGN KEY (`object_type_id`, `object_id`)
REFERENCES object_index (`object_type_id`, `object_id`));
在MySQL 5.6及更高版本中,您可以在每个表上定义一个虚拟/计算列,以匹配来自object_index的object_type_id而不是存储的物理列。
在MySQL 8.0和更高版本中,您也许可以在每个表上定义一个基于函数的索引,该表将鉴别符object_type_id包含为表达式,而不是表中的物理列或虚拟列。