Как я могу проверить ссылочную целостность в заданной строке после ее добавления? - PullRequest
3 голосов
/ 24 июня 2011

Я пытаюсь выяснить, есть ли способ проверить ссылочную целостность отдельной строки после ее вставки в таблицу 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;

Мы запустили против них следующие операторы:

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

Итак, мы поместили здесь несколько неверных данных - author_id ссылается на несуществующий person.id 3. Iя пытаюсь найти способ вызвать какую-либо проверку в этой строке, которая выдаст ошибку, если есть такая проблема с ссылками, как эта.

Подход, который я первоначально пытался применить, состоял в том, чтобы обновитьстрока с точно такими же данными.Я попробовал это:

UPDATE `book` SET `name` = 'Cryptonomicon', `author_id` = 3 WHERE `book`.`id` = 1 

Я ожидал, что это вызовет ошибку - однако, это не так.Поскольку данные не изменились, по-видимому, проверка целостности не производится?Например, если для параметра author_id установлено значение 2 , то завершится неудачей.

Мой вопрос: существует ли альтернатива, которая позволила бы мне проверить заданную строку и вызвать ошибку целостности в случае возникновения проблемы?Я погуглил, но ничего не нашел.Я хотел бы не проверять всю таблицу, но это может быть единственным маршрутом.

Любые идеи или другие подходы, которые избегают меня, будут оценены.

(Если вам любопытно почему Я пытаюсь сделать все это, потому что я пытаюсь помочь решить открытый вопрос в инфраструктуре Django, где не могут быть загружены приборы с прямыми ссылками. Предлагаемое решение:отключить проверки внешнего ключа при загрузке приборов и повторно включить их после завершения загрузки.Я пытаюсь выяснить, как в этот момент вернуться и проверить ссылочную целостность строк, которые были добавлены в то время как проверки внешнего ключа былиВыключить и вызвать ошибку, если есть проблема.)

Ответы [ 2 ]

6 голосов
/ 25 июня 2011

Я пришел к решению, к которому я действительно пришел благодаря ответу на этот вопрос: Заставить InnoDB перепроверить внешние ключи на столе / таблицах?

Я виделэтот вопрос раньше, но я, наконец, потратил около 20 минут, распаковывая все абстракции и пытаясь понять, что он делает в конкретных условиях.Это действительно не так уж и сложно, на самом деле.Если сформулировать ядро ​​решения в терминах примера, который я привел в этом вопросе, вы в основном получили два оператора SELECT:

SELECT *
FROM information_schema.KEY_COLUMN_USAGE
WHERE
    `CONSTRAINT_SCHEMA` LIKE `test`
    AND `TABLE_NAME` = `book`

, которые будут возвращать все ключевые столбцы в таблице 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

По сути, этот оператор будет возвращать любые строки, где есть значение в author_id, но нет соответствующего значениядля идентификатора в соответствующей таблице.Это «плохие строки».

Мне не нужно было вызывать ошибку непосредственно в MySQL - для своих целей я могу вызвать ошибку в коде приложения - так что это было настолько, насколько мне нужно былоидти.Но это оказалось довольно простым и быстрым решением, поэтому я рад, что нашел его!

1 голос
/ 25 июня 2011

Уловка ОБНОВЛЕНИЯ не работала, потому что MySQL проигнорировал обновление, поскольку ничего не изменилось:

UPDATE `book` SET
  `name` = 'Cryptonomicon',
  `author_id` = 3
WHERE `book`.`id` = 1;
Query OK, 0 rows affected (0.03 sec)
Rows matched: 1  Changed: 0  Warnings: 0

Поэтому вы можете обновить сначала другое значение, а затем вернуться к исходному значению, которое затем выдаст желаемую ошибку. Я завернул все это в транзакцию, чтобы ее можно было откатить, не затрагивая базу данных:

START TRANSACTION;

SET foreign_key_checks=0;

INSERT INTO `book` (`id`, `name`, `author_id`)
VALUES (1, 'Cryptonomicon', 3);

SET foreign_key_checks=1;

INSERT INTO `person` (`name`) VALUES ('NULL');

UPDATE `book` SET
  `author_id` = LAST_INSERT_ID()
WHERE `book`.`id` = 1;

UPDATE `book` SET
  `author_id` = 3
WHERE `book`.`id` = 1;

ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test`.`book`, CONSTRAINT `author_id_refs_id_7fdd0933` FOREIGN KEY (`author_id`) REFERENCES `person` (`id`))

ROLLBACK;

Это кажется грязным и потенциально опасным решением, но я недостаточно знаю об исходной проблеме ... Я также не знаю, действительно ли вы хотите сохранить исходное значение в таблице. Если вы это сделаете, вам придется снова отключить ограничения внешнего ключа, чтобы сбросить его!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...