两个外键,其中一个不是 NULL:如何在 SQL 中解决这个问题?

Bla*_*bam 8 mysql sql database-design innodb mysql-5.5

我有一张桌子time。时间条目(1:n 关系)要么属于project条目,要么属于special_work条目。必须设置项目 id 或 special_work id,两者都不是(exclusive 或)。

CREATE TABLE `time` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `project` int(20) NOT NULL,
  `special_work` int(20) NOT NULL,
  `date` date NOT NULL,
  `hours` float NOT NULL,
  `time_from` time DEFAULT NULL,
  `time_to` time DEFAULT NULL,
  `notes` text NOT NULL,
  PRIMARY KEY (`id`),
  FOREIGN KEY (`project`) REFERENCES `project`(`id`)
  FOREIGN KEY (`special_work`) REFERENCES `special_work`(`id`)
) DEFAULT CHARSET=utf8;
Run Code Online (Sandbox Code Playgroud)

我怎么能用SQL写这个?除了触发器还有什么办法吗?

如果您确定这是糟糕的数据库设计 - 有没有更好的方法来建模?不过,我希望有两个不同的时间表

我的数据库是 Mysql 5.5 InnoDB。

Gor*_*off 6

你的数据模型很好。在大多数数据库中,您还需要添加check约束:

alter table `time` add constraint chk_time_project_special_work
    check (project is not null xor special_work is null);
Run Code Online (Sandbox Code Playgroud)

但是,MySQL 不支持检查约束。如果您真的喜欢,您可以使用触发器来实现逻辑。


nvo*_*gel 5

像这样的互斥引用可能表明您的设计中缺少“超类型”表。考虑创建一个代表所有“工作”的新超类型表——项目和特殊工作。项目和特殊工作表将一对一地引用超类型表,其中包含所有项目/工作标识符的联合。然后,时间表只需要一个引用超类型的不可为空的外键。

  • 我认为这会简化事情。将 90% 的“不同”属性保留在 special_work 表中。将 10% 的共享属性移动到新的超类型表中。这里的工作原理是*正交设计*。您应该尽量避免在多个表中具有相同的属性。 (2认同)