添加行后,如何检查给定行中的参照完整性?

jsd*_*ton 4 mysql referential-integrity innodb

我正在尝试查看是否有一种方法可以在将单行插入InnoDB表时检查单行的参照完整性,同时foreign_key_checks将其设置为0.

所以给出两个表:

CREATE TABLE `book` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `author_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `book_cc846901` (`author_id`),
  CONSTRAINT `author_id_refs_id_7fdd0933` FOREIGN KEY (`author_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB;


CREATE TABLE `person` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
Run Code Online (Sandbox Code Playgroud)

我们针对它们运行以下语句:

SET foreign_key_checks=0
INSERT INTO `book` (`id`, `name`, `author_id`) VALUES (1, 'Cryptonomicon', 3)
INSERT INTO `person` (`id`, `name`) VALUES (4, 'Neal Stephenson')
SET foreign_key_checks=1
Run Code Online (Sandbox Code Playgroud)

所以我们在这里放了一些不好的数据 - author_id指的是不存在的person.id 3.我试图找到一种方法来触发该行的某种检查,如果存在引用问题则会引发错误像这个.

我最初尝试采用的方法是使用完全相同的数据更新行.我试过这个:

UPDATE `book` SET `name` = 'Cryptonomicon', `author_id` = 3 WHERE `book`.`id` = 1 
Run Code Online (Sandbox Code Playgroud)

我预计这会引发错误 - 但事实并非如此.由于数据没有变化,显然没有进行完整性检查?例如,将author_id设置为2 失败.

那么我的问题是:是否存在允许我检查给定行并在出现问题时触发完整性错误的替代方法?我用Google搜索了但我什么都没找到.我想避免检查整个表格,但这可能是唯一的路线.

任何逃避我的见解或其他方法都将受到赞赏.

(如果你很好奇我为什么要这么做,那是因为我正在尝试帮助解决Django框架中的一个开放问题,其中无法加载具有前向引用的灯具.建议的解决方案是禁用外键检查加载灯具并在加载完成后重新启用它们.我正在试图弄清楚当时如何返回并检查外键检查关闭时添加的行的引用完整性并引发如果有问题则出错.)

jsd*_*ton 7

我提出了一个解决方案,我实际上得益于这个问题的答案:强制InnoDB重新检查表/表上的外键?

我以前见过这个问题,但最后花了大约20分钟解开所有抽象包,并试图用具体的方式理解它在做什么.实际上,这真的不是那么复杂.根据我在这个问题中给出的例子来说明解决方案的核心,你基本上有两个SELECT语句:

SELECT *
FROM information_schema.KEY_COLUMN_USAGE
WHERE
    `CONSTRAINT_SCHEMA` LIKE `test`
    AND `TABLE_NAME` = `book`
Run Code Online (Sandbox Code Playgroud)

这将返回表中的所有键列book.我们可以迭代这些结果并检查它们的引用如下 - 在本例中使用"author_id":

SELECT * FROM `book` as REFERRING
LEFT JOIN `person` as REFERRED
ON (REFERRING.`author_id` = REFERRED.`id`)
WHERE REFERRING.`author_id` IS NOT NULL
AND REFERRED.`id` IS NULL
Run Code Online (Sandbox Code Playgroud)

基本上,该语句将返回author_id中存在值但在相关表中没有id的相应值的任何行.这些是"坏行".

我不需要直接在MySQL中触发错误 - 出于我的目的,我可以在应用程序代码中引发错误 - 所以这就是我需要去的地方.但这最终成为一个相当简单快速的解决方案,所以我很高兴我找到了它!