Как использовать RESTRICT для внешнего ключа в MySQL?

11

В структуре базы данных

  CREATE TABLE Country (
  name varchar(40) NOT NULL,
  PRIMARY KEY  (name)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE City (
  name varchar(40) NOT NULL,
  PRIMARY KEY  (name)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

CREATE TABLE Map (
  country varchar(40) NOT NULL,
  city varchar(100) NOT NULL,
  PRIMARY KEY  (country,city),
  FOREIGN KEY (country) REFERENCES Country (name) ON DELETE CASCADE,
  FOREIGN KEY (city) REFERENCES City (name) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Я ожидаю удалить родителя City, оставив соответствующее значение в потомке без изменений этими тремя равными командами

  FOREIGN KEY (city) REFERENCES City (name) ON DELETE NO ACTION
  FOREIGN KEY (city) REFERENCES City (name) ON DELETE RESTRICT
  FOREIGN KEY (city) REFERENCES City (name)

Но при использовании NO ACTIONИЛИ RESTRICTили опускании ON DELETE. MySQL не позволяет мне удалить из родительского столбца с этой ошибкой:

ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails 
('test'.'Map', CONSTRAINT 'Map_ibfk_2' FOREIGN KEY ('city') REFERENCES 'City'('name')
 ON DELETE RESTRICT

Где я не прав? Разве SQL не несет ответственности за NO ACTIONудаление родителя и оставление ребенка сиротой?

Googlebot
источник

Ответы:

13

Согласно документации MySQL по УДАЛЕНИЮ ОГРАНИЧЕНИЯ

• ОГРАНИЧЕНИЕ: отклоняет операцию удаления или обновления для родительской таблицы. Указание ОГРАНИЧЕНИЯ (или НЕТ ДЕЙСТВИЯ) - это то же самое, что опускание предложений ON DELETE или ON UPDATE.

Что касается бездействия

• NO ACTION: ключевое слово из стандартного SQL. В MySQL эквивалентен RESTRICT. InnoDB отклоняет операцию удаления или обновления для родительской таблицы, если в ссылочной таблице есть соответствующее значение внешнего ключа. Некоторые системы баз данных имеют отложенные проверки, и NO ACTION является отложенной проверкой. В MySQL ограничения внешнего ключа проверяются немедленно, поэтому NO ACTION - это то же самое, что и RESTRICT.

УДАЛЕНИЕ ОГРАНИЧЕНИЯ защищает родителя от удаления, а не детей.

RolandoMySQLDBA
источник
5

Если вы хотите удалить родителя и оставить ребенка, то, вероятно, вам нужна ON DELETE SET NULLопция:

SET NULL: удалить или обновить строку из родительской таблицы и установить для столбца или столбцов внешнего ключа в дочерней таблице значение NULL. Поддерживаются предложения ON DELETE SET NULL и ON UPDATE SET NULL.

Если вы указываете действие SET NULL, убедитесь, что вы не объявили столбцы в дочерней таблице как NOT NULL.

В последнем предложении много «не», поэтому просто убедитесь, что parent_id может быть NULL.

См. Также этот связанный вопрос: Какова цель SET NULL в ограничениях удаления / обновления внешних ключей?

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

Дерек Дауни
источник