2008-09-22 43 views
6

如果我在MySQL中有一个代表基类的表,并且我有一堆代表派生类中的字段的表,每个表都用外键引用基表,有没有办法让MySQL执行派生表和基表之间的一对一关系,还是必须在代码中完成?MySQL外键 - 如何跨表执行一对一的操作?

使用以下快速“N”脏架构作为一个例子,有没有什么办法让MySQL来确保两个product_cd和product_dvd行不能共享相同的product_id?是否有更好的方法来设计模式以允许数据库强制执行这种关系,还是根本无法实现?

CREATE TABLE IF NOT EXISTS `product` (
    `product_id` int(10) unsigned NOT NULL auto_increment, 
    `product_name` varchar(50) NOT NULL, 
    `description` text NOT NULL, 
    PRIMARY KEY (`product_id`) 
) ENGINE = InnoDB; 

CREATE TABLE `product_cd` (
    `product_cd_id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `product_id` INT UNSIGNED NOT NULL , 
    `artist_name` VARCHAR(50) NOT NULL , 
    PRIMARY KEY (`product_cd_id`) , 
    INDEX (`product_id`) 
) ENGINE = InnoDB; 

ALTER TABLE `product_cd` ADD FOREIGN KEY (`product_id`) 
    REFERENCES `product` (`product_id`) 
    ON DELETE RESTRICT ON UPDATE RESTRICT ; 

CREATE TABLE `product_dvd` (
    `product_dvd_id` INT UNSIGNED NOT NULL AUTO_INCREMENT , 
    `product_id` INT UNSIGNED NOT NULL , 
    `director` VARCHAR(50) NOT NULL , 
    PRIMARY KEY (`product_dvd_id`) , 
    INDEX (`product_id`) 
) ENGINE = InnoDB; 

ALTER TABLE `product_dvd` ADD FOREIGN KEY (`product_id`) 
    REFERENCES `product` (`product_id`) 
    ON DELETE RESTRICT ON UPDATE RESTRICT ; 

@Skliwz,可以请你提供有关触发器如何被用来执行这项约束与模式提供了更多的细节?

@boes,听起来不错。在有孩子的孩子的情况下,它是如何工作的?例如,如果我们添加了product_movie并将product_dvd作为product_movie的子项?将product_dvd的检查约束限制在所有子类型中是否会成为可维护性的噩梦?

+5

使用注释而不是编辑你的问题。 – epochwolf 2008-09-22 13:36:46

回答

3

为了确保产品是或CD或DVD我想补充一个类型列,并使其成为主键的一部分。在派生列中,为该类型添加检查约束。在示例中,我将cd设置为1,并且您可以为每个派生表制作DVD = 2等等。

CREATE TABLE IF NOT EXISTS `product` (
`product_id` int(10) unsigned NOT NULL auto_increment, 
'product_type' int not null, 
`product_name` varchar(50) NOT NULL, 
`description` text NOT NULL, 
PRIMARY KEY (`product_id`, 'product_type') 
) ENGINE = InnoDB; 

CREATE TABLE `product_cd` (
`product_id` INT UNSIGNED NOT NULL , 
'product_type' int not null default(1) check ('product_type' = 1) 
`artist_name` VARCHAR(50) NOT NULL , 
PRIMARY KEY (`product_id`, 'product_type') , 
) ENGINE = InnoDB; 

ALTER TABLE `product_cd` ADD FOREIGN KEY (`product_id`, 'product_type') 
REFERENCES `product` (`product_id`, 'product_type') 
ON DELETE RESTRICT ON UPDATE RESTRICT ; 
+2

-1。 MySQL忽略检查约束。 – 2012-06-28 01:49:03

1

如果您使用MySQL 5.x,则可以使用触发器来处理这些类型的约束。

另一个(次优)的办法是使用一个“类型”列在父表静静地忽略重复,并且能够选择正确的“扩展表”。

+1

你会如何使用这种约束的触发器?你能举个例子吗? – Shabbyrobe 2010-08-19 06:22:15

3

您可以将一个外键从一个主键添加到另一个主键。因为PK必须是唯一的,你可以自动获得一对一的关系。

+0

使用InnoDB,对我来说这是行不通的。即使在对剧本进行逆向工程之后,这种关系仍然是一对多的。维持一对一关系的唯一有效方法是将外键列设置为UNIQUE;这样我们确信只会为它创建一条记录。 如果你试图违反这个约束,你会得到下面的错误(MySQL 5.1): `1 error(s)save changes to table`testdb`.`table4`: INSERT INTO`testdb`.`table4`( (0,'soso',0) 1062:键'table3_idtable3_UNIQUE'' 回复完成' – Hanynowsky 2011-07-22 16:45:17

4

如果你摆脱了产品DVD-ID产品CD-ID的,以及所使用的产品ID为所有三个表的主键,你至少可以确保没有两张DVD或没有两张CD使用相同的产品编号。另外,会有更少的ID保持跟踪。

而且你也许需要某种产品表类型的列。

8

强制执行1:0-1或1:1间的关系可以通过定义外键的列的唯一约束,所以只有一个组合可以存在来实现。通常这将是子表的主键。

如果FK是对所引用的表的主要或唯一的密钥,将它们约束到存在于母体值和柱的唯一约束或列限制他们的独特性。这意味着子表只能具有与约束列中的父项对应的值,并且每行必须具有唯一值。这样做会强制子表最多只有一行对应于父记录。

+4

减1因为它不回答问题,并没有提供一个例子,仍然得到很多赞成票。部分问题是:'有没有什么方法可以确保product_cd和product_dvd中的行不能共享同一个product_id'。你不回答那个问题。谁给你这些赞成票? – boes 2011-07-22 17:06:58

1

保持一比一的关系,唯一有效的方法是外键列设置为UNIQUE;这样我们确信只会为它创建一条记录。如果你试图违反这个约束,你会得到以下错误(MySQL 5.1):

`1 error(s) saving changes to table testdb`.table4: INSERT INTO testdb.table4 (idtable4, label, table3_idtable3) VALUES (0, 'soso', 0) 1062: Duplicate entry '0' for key 'table3_idtable3_UNIQUE' Rollback complete