mysql - 将一个外键引用到多个可能的主键

时间:2012-07-16 10:47:33

标签: mysql database-design foreign-keys

我想设置以下数据库场景:

CREATE TABLE IF NOT EXISTS `points` (
  `po_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `po_north` INT,
  `po_east` INT,
  PRIMARY KEY (`po_id`),
) ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `lines`(
  `li_id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
  `li_from` INT NOT NULL,
  `li_to` INT NOT NULL,
  PRIMARY KEY (`li_id`),
  FOREIGN KEY (`li_from`) REFERENCES points(`po_id`),
  FOREIGN KEY (`li_to`) REFERENCES points(`po_id`),
) ENGINE=InnoDB;

现在我想设置一个第三个表,用于处理一些元数据,例如谁创建或更改了一个点或一行:

CREATE TABLE IF NOT EXISTS `metadata` (
  `me_type` ENUM('point','line') NOT NULL,
  `me_type_id` INT UNSIGNED NOT NULL,
  `me_permissions` VARCHAR(255) NOT NULL,
  `me_created_by` INT UNSIGNED NOT NULL,
  `me_created_on` DATETIME NOT NULL,
  `me_last_modified_by` INT UNSIGNED NOT NULL,
  `me_last_modified_by` DATETIME NOT NULL,
) ENGINE=InnoDB;

我的第一种方法是设置ENUM有两种类型(点和线)。但问题仍然是,我无法正确引用其中一个表的外键。在MySQL中是否有针对此类问题的推荐解决方案?

顺便说一句: me_created_byme_last_modified_by的字段应引用存储某些用户数据的表。

3 个答案:

答案 0 :(得分:1)

您的案例似乎是设计模式的另一个实例,称为“泛化专业化”或“类继承的表设计”。

如果将点和线视为对象类,它们都是一些更通用的对象类的子类。在这种情况下,我不确定给出超类的名称。以下是解决同一问题的几个问题之一。

Extending classes in the database

Fowler对该主题进行了广泛的治疗。您的案例有一个额外的皱纹,因为您正在处理元数据。但这不需要改变设计。你需要第三张桌子,因为缺少一个更好的术语,我称之为“项目”。键“it_id”将被分配一个自动编号,每次添加一个点或一行时都会添加一个项目。两列“po_id”和“li_id”不会被分配一个自动编号。相反,它们将是外键,在Items表中引用“it_id”。

元数据表中对点或线的引用将引用“项目”,您可以根据具体情况使用该信息查找有关点或线的信息。

这有多大帮助取决于您尝试使用元数据做什么。

答案 1 :(得分:0)

您的表格pointslines应该包含metadata的外键 - 而不是相反。这样做可以避免定义任何更复杂的表设置。使用这种方法,对于许多不同的点或线,可以多次重复使用单个metadata条目。这甚至不是MySQL特有的,而是一般的标准化数据库结构。

答案 2 :(得分:-1)

你可以使用触发器执行此操作,在根据相应的表插入记录之前,需要触发可以为点或行创建引用键的事件