MySQL:破解外键实现?

用于在
MySQL中定义外键的内联语法似乎没有做任何事情,而较长的CONSTRAINT语法似乎按预期工作.我很好奇为什么会这样.

我最近发现用于定义外键的内联语法(我认为它可以正常工作)不会对参照完整性进行任何实际检查. ON DELETE / UPDATE子句中定义的内容无关紧要.
我当然用InnoDB尝试了这个,因为我知道MyISAM不支持外键检查.

请看一下示例/小提琴,你会明白我的意思.

内联语法

这是根据我多年来使用的文档定义外键的正确方法.

-- 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语法

使用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(您必须取消注释左侧的最后一个语句才能看到它失败)

结论/实际问题

正如你在fiddles中看到的那样,用于创建外键的内联语法似乎没有做任何事情,而较长的CONSTRAINT语法可以正常工作.

有谁知道为什么会这样?有什么理由或者这只是我们必须解决的另一个MySQL怪癖吗?
请分享你的知识,我很好奇.

更新/显示CREATE TABLE验证

这是@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

CONSTRAINT语法

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)作为错误提交,似乎已经知道了一段时间.我真的希望他们至少会更新有关这方面的文件,因为我认为这不会很快修复.

最佳答案 我以前唯一知道的“短语法”是:

create_definition:
    col_name column_definition
...
    | [CONSTRAINT [symbol]] FOREIGN KEY
      [index_name] (index_col_name,...) reference_definition

reference_definition:
    REFERENCES tbl_name (index_col_name,...)
      [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
      [ON DELETE reference_option]
      [ON UPDATE reference_option]

注意强制FOREIGN KEY子句.

但是,解析器确实接受您使用的“更短语法”,in accordance with the manual

column_definition:
    data_type [NOT NULL | NULL] [DEFAULT default_value]
...
      [reference_definition]

注意缺少FOREIGN KEY子句.

事实上,这种奇怪的行为记录在同一页面中:

MySQL parses but ignores “inline REFERENCES specifications” (as
defined in the SQL standard) where the references are defined as part
of the column specification. MySQL accepts REFERENCES clauses only
when specified as part of a separate FOREIGN KEY specification.

该限制也在in the tutorial中进行了更广泛的讨论.

这是一个错误还是一个缺失的功能has been long debated,所以看来.

点赞