2008-09-22 36 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 
相關問題