允许NULL时,未实施复合外键约束,任何解决方案?

时间:2016-02-06 11:45:55

标签: mysql triggers foreign-keys

我正在使用mysql 5.6.20并且我有以下架构:

项目活动表:

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)

奇怪的是,它甚至接受不在父表中的数据。

只有当所有列都包含数据时,外国关键约束才会受到影响吗?

如果任何列包含数据或所有列必须为NULL,我想强制执行约束。

Mysql Doc。说,(link)

  

SQL标准中的MATCH子句控制a中NULL值的方式   比较时处理复合(多列)外键   主键。 MySQL本质上实现了定义的语义   MATCH SIMPLE,允许外键全部或部分为NULL。   在这种情况下,包含这样的外键的(子表)行是   允许插入,并且与引用的任何行都不匹配   (父)表。可以使用实现其他语义   触发器。

我不能将“NOT NULL”作为基本要求。我在str_transaction表中有许多其他字段(与问题无关)在此处删除,以便更清楚地说明问题。

按照文档中的建议实施触发器是一种好习惯吗?或者任何人都可以帮我设计架构吗?

1 个答案:

答案 0 :(得分: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