在 MySQL 中定义外键的内联语法似乎没有任何作用,而较长的 CONSTRAINT 语法似乎按预期工作。我很好奇为什么会发生这种情况。
我最近发现用于定义外键的内联语法(我认为它可以正常工作)并没有对参照完整性进行任何实际检查。 ON DELETE/UPDATE 子句中定义了什么并不重要。
我当然已经用 InnoDB 试过了,因为我知道 MyISAM 不支持外键检查。
请查看示例/ fiddle ,您会明白我的意思。
内联语法
这是根据文档定义外键的正确方法,我已经使用了多年。
-- Create a basic foreign key relationship.
CREATE TABLE `parent` (
`id` INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`a` VARCHAR(255) NOT NULL
)ENGINE=InnoDB; -- Just to be sure.
CREATE TABLE `child` (
`id` INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
-- Short legitimate syntax, frequently used.
`parent_id` INTEGER UNSIGNED NOT NULL REFERENCES `parent` (`id`)
ON DELETE RESTRICT
)ENGINE=InnoDB; -- Just to be sure.
现在,如果我从 父 表中删除一行,该表在 子 表中引用,它会被删除,就像我从未定义外键一样。
自己试试:Fiddle
约束语法
使用 CONSTRAINT 关键字的较长语法编写起来更麻烦,但与内联定义相比,它似乎按预期工作。
-- `parent` table has been omitted, since it is the same as above.
CREATE TABLE `child` (
`id` INTEGER UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`parent_id` INTEGER UNSIGNED NOT NULL,
-- Longer, more cumbersome syntax.
CONSTRAINT `fk_child_parent` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)
ON DELETE RESTRICT
)ENGINE=InnoDB; -- Just to be sure.
如果我尝试从 父 中删除引用的行,它会按预期失败。
自己尝试一下:Fiddle(您必须取消对左侧最后一条语句的注释才能看到它失败)
结论/实际问题
正如您在 fiddle 中亲眼所见,用于创建外键的内联语法似乎没有任何作用,而较长的 CONSTRAINT 语法工作正常。
有谁知道为什么会这样?是否有任何原因,或者这只是我们必须解决的另一个 MySQL 怪癖?
请分享您的知识,我很好奇。
更新/显示创建表验证
这是@MikePurcell 指出的
SHOW CREATE TABLE
的输出。“短”语法
CREATE TABLE `child`(
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
约束语法
CREATE TABLE `child` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`parent_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_child_parent` (`parent_id`),
CONSTRAINT `fk_child_parent` FOREIGN KEY (`parent_id`) REFERENCES `parent` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
现在很明显,解析器使用“short”语法简单地忽略了表定义中的
REFERENCES
子句。至少文档更新会有所帮助。谢谢你们的帮助。仅供引用: 这早在 2004 年就已作为错误提交( Bug #4919 ),并且似乎更久了。我真的希望他们至少会更新与此相关的文档,因为我认为这不会很快得到修复。
最佳答案
我曾经知道的唯一“简短语法”是:
创建定义:
col_name column_definition
...
| [CONSTRAINT [符号]] 外键
[index_name] (index_col_name,...) reference_definition
引用定义:
引用 tbl_name (index_col_name,...)
[匹配满 |匹配部分 |匹配简单]
[ON DELETE reference_option]
[ON UPDATE reference_option]
注意强制性的 FOREIGN KEY
子句。
但是,解析器确实接受您使用的“更短的语法”, in accordance with the manual :
列定义:
数据类型 [非空 | NULL] [DEFAULT default_value]
...
[引用定义]
注意缺少 FOREIGN KEY
子句。
事实上,这种奇怪的行为记录在同一页面中:
也更广泛地讨论了限制 in the tutorial 。
无论这是错误还是缺失的功能 has been long debated ,看起来都是如此。
关于MySQL:损坏的外键实现?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29284562/