Ошибка ограничения фиктивного внешнего ключа

110

Я получаю это сообщение об ошибке:

ОШИБКА 1217 (23000) в строке 40: невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не выполнено.

... когда я пытаюсь сбросить стол:

DROP TABLE IF EXISTS `area`;

... определяется так:

CREATE TABLE `area` (
  `area_id` char(3) COLLATE utf8_spanish_ci NOT NULL,
  `nombre_area` varchar(30) COLLATE utf8_spanish_ci NOT NULL,
  `descripcion_area` varchar(100) COLLATE utf8_spanish_ci NOT NULL,
  PRIMARY KEY (`area_id`),
  UNIQUE KEY `nombre_area_UNIQUE` (`nombre_area`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_spanish_ci;

Забавно то, что я уже отбросил все другие таблицы в схеме, против которых есть внешние ключи area. Собственно база пуста, кроме areaтаблицы.

Как у него могут быть дочерние строки, если в базе данных нет другого объекта? Насколько я знаю, InnoDB не позволяет использовать внешние ключи для других схем, не так ли?

(Я даже могу запустить RENAME TABLE area TO something_elseкоманду: -?)

Альваро Гонсалес
источник
Возможно ли, что таблица является частью отношения ссылочной целостности в другой схеме?
Raj More
У меня есть другие копии приложения, так что это всегда возможно. Однако я использую в основном синтаксис CONSTRAINT fk_servicio_area1 FOREIGN KEY (area_id) REFERENCES area (area_id), т. Е. Без имени схемы в ссылке на таблицу: -?
Álvaro González

Ответы:

101

Две возможности:

  1. В другой схеме есть таблица («база данных» в терминологии mysql), которая имеет ссылку на FK
  2. Внутренний словарь данных innodb не синхронизирован со словарем mysql.

Вы можете увидеть, какая это была таблица (во всяком случае, одна из них), выполнив «SHOW ENGINE INNODB STATUS» после сбоя сброса.

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

MySQL 5.1 и выше выдаст вам имя таблицы с FK в сообщении об ошибке.

MarkR
источник
1
Я больше не могу воспроизвести проблему. Несинхронизированный словарь является вероятной причиной. Я протестирую его день и посмотрю, что SHOW ENGINE INNODB STATUSсообщает.
Álvaro González,
3
Спасибо за такой ответ! У меня была таблица "многие ко многим", которая все еще ссылалась на таблицу, которую мы не могли удалить, поэтому мне пришлось сначала отбросить эту таблицу.
Christian Oudard
5
SHOW ENGINE INNODB STATUS перечисляет последнюю ошибку внешнего ключа в разделе «ПОСЛЕДНЯЯ ОШИБКА ИНОСТРАННОГО КЛЮЧА». Это отметка времени.
bbrame
может существовать таблица, по-прежнему имеющая ссылочный ключ к тематической таблице. это было в моем случае вот так.
RT
Сэкономлено много времени. Отбросил db в разделе "ПОСЛЕДНЯЯ ОШИБКА ИНОСТРАННОГО КЛЮЧА"
Sand1512
121

По запросу, теперь как ответ ...

При использовании MySQL Query Browser или phpMyAdmin создается впечатление, что для каждого запроса открывается новое соединение ( bugs.mysql.com/bug.php?id=8280 ), поэтому необходимо записывать все операторы drop в одном запросе, например.

SET FOREIGN_KEY_CHECKS=0; 
DROP TABLE my_first_table_to_drop; 
DROP TABLE my_second_table_to_drop; 
SET FOREIGN_KEY_CHECKS=1; 

Где SET FOREIGN_KEY_CHECKS=1служит дополнительной мерой безопасности ...

Карлис Роде
источник
2
Для тех, кто создает дамп с помощью phpMyAdmin, есть опция «Отключить проверку внешнего ключа», которая автоматически добавляется SET FOREIGN_KEY_CHECKS=0;в начало дампа.
Майк,
Похоже, что phpMyAdmin реализовал эту прекрасную функцию, теперь я жду, когда mysqlWorkbench сделает то же самое! :)
Карлис Роде
@CodeMed К вашему сведению, я принял ответ MarkR, потому что он дает объяснение проблемы, которая имеет смысл, хотя я признаю, что не мог проверить это, поскольку я не сталкивался с этой же проблемой в течение следующих 6 лет, ни разу. Этот и более ранние ответы предоставляют обходной путь (отлично подходит для этого), но на самом деле не затрагивают сам вопрос, и поскольку вы можете принять только один ответ, мне пришлось выбрать.
Álvaro González
1
Предупреждение: это не решение, а только обходной путь ленивого человека. После использования этого (с записями в некоторых других таблицах, указывающими на отброшенную таблицу) вы столкнетесь с зависшими внешними ключами, которые фатально нарушают согласованность ( C в ACID ) вашей базы данных, и ваши приложения начнут генерировать исключения повсюду. Вас предупредили.
bekce 07
Хотя я уверен, что предупреждение bekce следует понять и прислушаться, это решение действительно сработало для меня в ситуации, когда я был уверен, что я также удалял все таблицы, которые указывали на таблицы с неприятными ограничениями внешнего ключа.
user1147171
47

Отключить проверку внешнего ключа

SET FOREIGN_KEY_CHECKS=0
Flakron Bytyqi
источник
62
Кажется, что SET FOREIGN_KEY_CHECKS=0это правильная команда, и она исправляет сообщение об ошибке. Вы хоть представляете, зачем это нужно? Кэшируются ли внешние ключи даже после удаления таблиц?
Álvaro González,
1
По правде говоря, я понятия не имею, почему возникает такая проблема, но убедитесь, что вы отключаете проверку ключей каждый раз, когда вносите какие-то огромные изменения или обновления. Это случалось со мной несколько раз, в результате чего я не спал несколько дней.
Flakron Bytyqi
55
Обязательно сделайте это SET FOREIGN_KEY_CHECKS=1;после того, как закончите!
pedro_sland
5
При использовании MySQL Query Browser или phpMyAdmin создается впечатление, что для каждого запроса открывается новое соединение ( bugs.mysql.com/bug.php?id=8280 ), поэтому необходимо записывать все операторы drop в одном запросе, например. SET FOREIGN_KEY_CHECKS=0; DROP TABLE my_first_table_to_drop; DROP TABLE my_second_table_to_drop; SET FOREIGN_KEY_CHECKS=1; Где SET FOREIGN_KEY_CHECKS = 1 служит дополнительной мерой безопасности ...
Карлис Роде
1
@KarlisRode, Bravo за комментарий к phpMyAdmin. Если бы вы сформулировали это как ответ, я бы добавил +1.
Sablefoste
28

из этого блога :

Вы можете временно отключить проверку внешнего ключа:

SET FOREIGN_KEY_CHECKS=0;

Просто не забудьте восстановить их, когда закончите возиться:

SET FOREIGN_KEY_CHECKS=1;
JackD
источник
Хороший ответ, так как я развивался на местном :)
Аделин
Это допустимый обходной путь (я могу подтвердить, что он работает), но связанная запись в блоге на самом деле не говорит о сценарии в этом вопросе (база данных, которая уже пуста, за исключением одной таблицы).
Альваро Гонсалес,
6

надеюсь его работа

УСТАНОВИТЬ foreign_key_checks = 0; ТАБЛИЦА ПАДЕНИЯ table name; УСТАНОВИТЬ foreign_key_checks = 1;

M_ Fa
источник
Да, это работает, как неоднократно упоминалось ранее ;-)
Альваро Гонсалес
1

В Rails можно делать следующее, используя rails console:

connection = ActiveRecord::Base.connection
connection.execute("SET FOREIGN_KEY_CHECKS=0;")
эйо
источник
0

Возможно, вы раньше получали ошибку при работе с этой таблицей. Вы можете переименовать таблицу и попробовать удалить ее снова.

ALTER TABLE `area` RENAME TO `area2`;
DROP TABLE IF EXISTS `area2`;
Вадим Плужинский
источник
0

Я нашел простое решение: экспортируйте базу данных, отредактируйте то, что вы хотите отредактировать, в текстовом редакторе, а затем импортируйте. Готово

Абдулрахман К
источник
4
Это интересное решение, которого на самом деле не должно быть. Вместо этого все, что нужно изменить, следует делать через СУБД. Редактирование дампа базы данных в текстовом редакторе кажется хорошим источником проблем.
Брэндон Анзалди,
1
Я действительно не понимаю, чем ты занимаешься. Выгрузка базы данных, удаление CREATE TABLEкода и повторная загрузка дампа ... не заставит MySQL удалить таблицу. И если вы имеете в виду восстановление дампа в новой базе данных ... Если вы хотите стереть все таблицы, как я, вновь созданная база данных будет уже пустой. Если вы хотите сохранить несколько таблиц, SET FOREIGN_KEY_CHECKS=0обходной путь, упомянутый здесь повсюду, работает нормально и проще; и вам, вероятно, в любом случае не нужно редактировать дамп, поскольку новая копия ваших данных, возможно, не будет иметь несинхронизированного словаря данных.
Álvaro González
-1

Невозможно удалить или обновить родительскую строку: ограничение внешнего ключа не выполняется ( table1. user_role, CONSTRAINT FK143BF46A8dsfsfds@#5A6BD60FOREIGN KEY ( user_id) REFERENCES user( id))

Что я сделал в два простых шага. сначала я удаляю дочернюю строку в дочерней таблице, например

mysql> удалить из таблицы2, где role_id = 2 && user_id = 20;

Запрос в порядке, затронута 1 строка (0,10 сек)

и второй шаг как удаление родителя

удалить из таблицы1, где id = 20;

Запрос в порядке, затронута 1 строка (0,12 сек)

Этим я решаю проблему, что означает Удалить ребенка, затем удалить родителя

Надеюсь, ты понял. :)

Адиль Масавир
источник
Пожалуйста, прочтите вопрос еще раз. Вы не можете удалить таблицу, которой не существует.
Álvaro González
в этом сценарии мы можем удалить ограничение внешнего ключа, а затем попытаться удалить таблицу. мы можем отбросить внешний ключ, например, ALTER TABLE <TABLE_NAME> DROP CONSTRAINT <FOREIGN_KEY_NAME>
Адил Масавир