在 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/

10-14 11:08
查看更多