【发布时间】:2017-05-08 16:33:42
【问题描述】:
我遇到了 MySQL 5.6 InnoDb 在运行 INSERT INTO xxx (col) SELECT ... 时忽略 NOT NULL 外键的问题。以其他格式运行插入语句时,会正确执行该约束。启用外键检查,sql_mode = STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ENGINE_SUBSTITUTION
这是一个例子:
CREATE TABLE Test_Parent
(
id BIGINT(18) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
dummy VARCHAR(255)
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci
COMMENT 'Test parent table';
CREATE TABLE Test_Child
(
id BIGINT(18) unsigned PRIMARY KEY NOT NULL AUTO_INCREMENT,
fid BIGINT UNSIGNED NOT NULL,
FOREIGN KEY Fk_Test_Parent_01(fid) REFERENCES Test_Parent(id)
) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_unicode_ci
COMMENT 'Test child table';
INSERT INTO Test_Parent(dummy)
VALUES ('test');
## Here's where the FK constraint should be enforced but isn't ##
INSERT INTO Test_Child(fid)
SELECT id
FROM Test_Parent
WHERE dummy = 'missing value';
1 row affected in 5ms
## Running an insert with a different format, the constraint is enforced ##
INSERT INTO Test_Child(fid)
VALUES (null);
Column 'fid' cannot be null
## Running this format, the foreign key is also enforced ##
INSERT INTO Test_Child(id, fid)
VALUES (123, (SELECT id FROM Test_Parent WHERE dummy = 'missing value'));
Column 'fid' cannot be null
我不明白为什么 MySQL 会为 3 个插入语句中的 2 个强制执行外键。有什么想法吗?
【问题讨论】:
-
我想知道您是否看到错误报告的“1 行受影响”,因为
INSERT...SELECT实际上并没有导致任何行插入,因为WHERE子句不匹配。如果我从两个表中SELECT *,我在Test_Child中看不到任何行...sqlfiddle.com/#!9/7413e0/1 -
也就是说,除非您的真实数据和用例与您为我们设置的测试集有显着差异。
-
没错 - 它报告插入了 1 行,但实际上没有任何内容插入到表中。我希望在这种情况下强制执行
NOT NULL约束。相反,就好像异常被吞没了一样。 -
但是在你的真实测试数据中,
WHERE dummy = 'missing value'真的返回一行吗?如果不是,它将始终导致插入零行,因此不会违反 FK。但是您的 MySQL 版本可能在受影响的行输出中存在错误。我在 5.7 和 5.6.35 上尝试过,但我的两个都报告插入了零行而不是 1。 -
因为如果没有来自
SELECT的行,它甚至不会尝试插入。它与您的第三个示例不同,其中文字123强制插入行以及从子选择返回的NULL。如果您尝试了类似INSERT INTO Test_Child (fid) SELECT NULL FROM Test_Parent的方法,其中 select 确实返回了具有NULL值的行,那么您应该会遇到 FK 违规。
标签: mysql foreign-keys constraints notnull insert-select