2016-02-06 51 views
0

我使用的MySQL 5.6.20和我有以下模式:允許NULL時強制實施複合外鍵約束,任何解決方案?

項目活動表:

CREATE TABLE `prj_project_activity_detail` (
    `fkPrjProjectActivity` VARCHAR(128) NOT NULL, 
    `fkPrjProjectActivitySub` VARCHAR(128) NOT NULL, 
    `fkProjectId` INT(10) UNSIGNED NOT NULL, 
    PRIMARY KEY (`fkPrjProjectActivity`, `fkPrjProjectActivitySub`, `fkProjectId`), 
    INDEX `FK__prj_project_activity` (`fkPrjProjectActivity`, `fkProjectId`), 
    INDEX `FK__prj_project_activity_2` (`fkPrjProjectActivitySub`, `fkProjectId`), 
    CONSTRAINT `FK__prj_project_activity` FOREIGN KEY (`fkPrjProjectActivity`, `fkProjectId`) REFERENCES `prj_project_activity` (`PrjProjectActivity`, `fkProjectId`) ON UPDATE CASCADE, 
    CONSTRAINT `FK__prj_project_activity_2` FOREIGN KEY (`fkPrjProjectActivitySub`, `fkProjectId`) REFERENCES `prj_project_activity` (`PrjProjectActivity`, `fkProjectId`) ON UPDATE CASCADE 
) 
COLLATE='utf8_general_ci' 
ENGINE=InnoDB; 

數據:

fkPrjProjectActivity fkPrjProjectActivitySub  fkProjectId 
Activity 1     Sub Activity 1    1 
Activity 1     Sub Activity 2    1 
Activity 1     Sub Activity 3    1 

交易表:

CREATE TABLE `str_transaction` (
    `StrTransactionId` VARCHAR(32) NOT NULL, 
    `fkPrjProjectActivity` VARCHAR(128) NULL DEFAULT NULL, 
    `fkPrjProjectActivitySub` VARCHAR(128) NULL DEFAULT NULL, 
    `fkProjectId` INT(10) UNSIGNED NULL DEFAULT NULL, 
    PRIMARY KEY (`StrTransactionId`), 
    INDEX `FK_str_transaction_department` (`fkTransactionForStoreDepartmentId`), 
    INDEX `FK_str_transaction_prj_project_activity_detail` (`fkPrjProjectActivity`, `fkPrjProjectActivitySub`, `fkProjectId`), 
    CONSTRAINT `FK_str_transaction_prj_project_activity_detail` FOREIGN KEY (`fkPrjProjectActivity`, `fkPrjProjectActivitySub`, `fkProjectId`) REFERENCES `prj_project_activity_detail` (`fkPrjProjectActivity`, `fkPrjProjectActivitySub`, `fkProjectId`) ON UPDATE CASCADE, 
) 
COLLATE='utf8_general_ci' 
ENGINE=InnoDB; 

預期實施數據:

StrTransactionId fkPrjProjectActivity fkPrjProjectActivitySub  fkProjectId 
1      Activity 1     Sub Activity 2   1 
2      Activity 1     Sub Activity 3   1 

但它讓我插入任何數據如下圖所示:

意想不到的結果:

StrTransactionId fkPrjProjectActivity fkPrjProjectActivitySub  fkProjectId 
1      Dummy 1     Sub Activity 2    (NULL) 
2      Activity 1    (NULL)      1 
3      Dummy 1     Dummy 1      (NULL) 

奇怪的是,它甚至接受其不在父表中的數據。

只有當所有列包含數據時,FOREIGN KEY約束纔會生效嗎?

如果任何一列包含數據或所有列必須爲NULL,我想強制約束。

Mysql Doc。說,(link)

在SQL標準控制如何進行比較來 主鍵時在 複合(多列)的外鍵NULL值處理的MATCH子句。 MySQL本質上實現了 MATCH SIMPLE定義的語義,它允許外鍵全部或部分爲NULL。 在這種情況下,包含這種外鍵的(子表)行允許插入 ,並且與引用的 (父)表中的任何行都不匹配。使用 觸發器可以實現其他語義。

由於是基本要求,我不能製作「NOT NULL」。我在str_transaction表中有許多其他字段(與問題無關)在此處被刪除,以便更清楚地說明問題。

按照文檔中的建議實施觸發器是否是一種好的做法?或者任何人都可以幫助我設計架構?

+1

爲什麼不'prj_project_activity_detail'你的組合自然的,而不是使用合成PK? – eggyal

回答

0

像eggyal建議,我會創建一個prj_project_activity_detail表的自動增量主鍵和str_transaction表的引用它的外鍵。

結構可能看起來像:

CREATE TABLE `prj_project_activity_detail` (
    `prjProjectActivityDetailId` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `fkPrjProjectActivity` VARCHAR(128) NOT NULL, 
    `fkPrjProjectActivitySub` VARCHAR(128) NOT NULL, 
    `fkProjectId` INT(10) UNSIGNED NOT NULL, 
    PRIMARY KEY (`prjProjectActivityDetailId`), 
    INDEX `FK__prj_project_activity` (`fkPrjProjectActivity`, `fkProjectId`), 
    INDEX `FK__prj_project_activity_2` (`fkPrjProjectActivitySub`, `fkProjectId`), 
    CONSTRAINT `FK__prj_project_activity` FOREIGN KEY (`fkPrjProjectActivity`, `fkProjectId`) REFERENCES `prj_project_activity` (`PrjProjectActivity`, `fkProjectId`) ON UPDATE CASCADE, 
    CONSTRAINT `FK__prj_project_activity_2` FOREIGN KEY (`fkPrjProjectActivitySub`, `fkProjectId`) REFERENCES `prj_project_activity` (`PrjProjectActivity`, `fkProjectId`) ON UPDATE CASCADE 
) 
COLLATE='utf8_general_ci' 
ENGINE=InnoDB; 

CREATE TABLE `str_transaction` (
    `StrTransactionId` VARCHAR(32) NOT NULL, 
    `fkPrjProjectActivityDetailId` INT(10) UNSIGNED NULL DEFAULT NULL, 
    PRIMARY KEY (`StrTransactionId`), 
    INDEX `FK_str_transaction_prj_project_activity_detail` (`fkPrjProjectActivityDetailId`), 
    CONSTRAINT `FK_str_transaction_prj_project_activity_detail` FOREIGN KEY (`fkPrjProjectActivityDetailId`) REFERENCES `prj_project_activity_detail` (`prjProjectActivityDetailId`) ON UPDATE CASCADE 
) 
COLLATE='utf8_general_ci' 
ENGINE=InnoDB; 

現在,你將無法在你的例子一樣插入無效數據,因爲你的foregn關鍵是一個現有prjProjectActivityDetailIdNULL

爲了模擬舊str_transaction表,你可以創建一個左視圖加入:

CREATE VIEW `str_transaction_view` AS 
    SELECT 
     st.StrTransactionId, 
     pad.fkPrjProjectActivity, 
     pad.fkPrjProjectActivitySub, 
     pad.fkProjectId 
    FROM str_transaction st 
    LEFT JOIN prj_project_activity_detail pad 
     ON pad.prjProjectActivityDetailId = st.fkPrjProjectActivityDetailId; 

Sample