Как изменить ссылочное действие внешнего ключа? (поведение)

102

Я создал таблицу, содержащую столбец с внешним ключом, для которого установлено значение ON DELETE CASCADE(удалить дочерний элемент при удалении родителя)

Какой должна быть команда SQL, чтобы это изменить ON DELETE RESTRICT? (нельзя удалить родителя, если у него есть дети)

Моак
источник

Ответы:

170

Старый вопрос, но добавлен ответ, чтобы можно было получить помощь

Его двухэтапный процесс:

Предположим, у a table1есть внешний ключ с именем столбца fk_table2_id, с именем ограниченияfk_name и table2указана таблица с ключом t2( что-то вроде ниже на моей диаграмме ).

   table1 [ fk_table2_id ] --> table2 [t2]

Первый шаг , УДАЛИТЬ старое ОГРАНИЧЕНИЕ: ( ссылка )

ALTER TABLE `table1` 
DROP FOREIGN KEY `fk_name`;  

ограничение уведомления удаляется, столбец не удаляется

Второй шаг , ДОБАВИТЬ новое ОГРАНИЧЕНИЕ:

ALTER TABLE `table1`  
ADD CONSTRAINT `fk_name` 
    FOREIGN KEY (`fk_table2_id`) REFERENCES `table2` (`t2`) ON DELETE CASCADE;  

добавление ограничения, столбец уже есть

Пример:

У меня UserDetailsтаблица относится к Usersтаблице:

mysql> SHOW CREATE TABLE UserDetails;
:
:
 `User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`)
:
:

Первый шаг:

mysql> ALTER TABLE `UserDetails` DROP FOREIGN KEY `FK_User_id`;
Query OK, 1 row affected (0.07 sec)  

Второй шаг:

mysql> ALTER TABLE `UserDetails` ADD CONSTRAINT `FK_User_id` 
    -> FOREIGN KEY (`User_id`) REFERENCES `Users` (`User_id`) ON DELETE CASCADE;
Query OK, 1 row affected (0.02 sec)  

результат:

mysql> SHOW CREATE TABLE UserDetails;
:
:
`User_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`Detail_id`),
  KEY `FK_User_id` (`User_id`),
  CONSTRAINT `FK_User_id` FOREIGN KEY (`User_id`) REFERENCES 
                                       `Users` (`User_id`) ON DELETE CASCADE
:
Гриджеш Чаухан
источник
2
Разве добавляемое ограничение не должно быть ON DELETE RESTRICT, как того требует исходный вопрос?
Noumenon
Эм, что такое «каскад удаления» и почему это необходимо?
Lealo
3
@Noumenon RESTRICT - это значение по умолчанию, поэтому вы получите его, если не укажете.
edruid
1
@Lealo «при каскаде удаления» означает, что если вы удаляете строку из родительской таблицы (в данном случае «Пользователи»), все ссылающиеся на нее строки из дочерней таблицы (UserDetails) также удаляются.
edruid
1
спасибо за примечания «ограничение уведомления удалено, столбец не удален», «добавлено ограничение, столбец уже существует», предполагаю, что это означает, что данные практически сохраняются и там изменяется только схема
Джордж Бирбилис
21

Вы можете сделать это одним запросом, если хотите изменить его имя:

ALTER TABLE table_name
  DROP FOREIGN KEY `fk_name`,
  ADD CONSTRAINT `fk_name2` FOREIGN KEY (`remote_id`)
    REFERENCES `other_table` (`id`)
    ON DELETE CASCADE;

Это полезно для минимизации времени простоя, если у вас большой стол.

Ромуальд Брюне
источник
12
ALTER TABLE DROP FOREIGN KEY fk_name;
ALTER TABLE ADD FOREIGN KEY fk_name(fk_cols)
            REFERENCES tbl_name(pk_names) ON DELETE RESTRICT;
паскаль
источник
2
помог мне найти решение ALTER TABLE table_name ADD...ON DELETE RESTRICT
Моак
3
Нет, fk_name - это имя ограничения. Предоставлять его необязательно. Я не уверен, но, возможно, вы сможете получить его с помощью SHOW CREATE TABLE.
Pascal
1
ON CASCAD RESTRICT, вероятно, не предназначен.
jgreep 06
5

Помните, что MySQL сохраняет простой индекс для столбца после удаления внешнего ключа. Итак, если вам нужно изменить столбец «ссылки», вы должны сделать это за 3 шага.

  • бросить оригинальный FK
  • удалить индекс (имена как предыдущий fk, используя drop indexпредложение)
  • создать новый FK
Василий
источник
3

Вы можете просто использовать один запрос, чтобы управлять ими всеми: ALTER TABLE products DROP FOREIGN KEY oldConstraintName, ADD FOREIGN KEY (product_id, category_id) REFERENCES externalTableName (foreign_key_name, another_one_makes_composite_key) ON DELETE CASCADE ON UPDATE CASCADE

заикающийся
источник
1
это будет работать, только если вы измените имя ограничения (если вы используете автоматически сгенерированное имя, вероятно, это сработает, предполагаю, что MySQL всегда создает уникальные)
Джордж Бирбилис
Запрос точно работает на MySQL / MariaDB. Ключевым моментом здесь является
отказ
1
синтаксис
универсального
3

Мне нужно было изменить кучу FK, поэтому я написал что-то, чтобы сделать заявления за меня. Прикинул, что поделюсь:

SELECT

CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` DROP FOREIGN KEY `' ,rc.CONSTRAINT_NAME,'`;')
, CONCAT('ALTER TABLE `' ,rc.TABLE_NAME,
    '` ADD CONSTRAINT `' ,rc.CONSTRAINT_NAME ,'` FOREIGN KEY (`',kcu.COLUMN_NAME,
    '`) REFERENCES `',kcu.REFERENCED_TABLE_NAME,'` (`',kcu.REFERENCED_COLUMN_NAME,'`) ON DELETE CASCADE;')

FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
LEFT OUTER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
    ON kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
    AND kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
WHERE DELETE_RULE = 'NO ACTION'
AND rc.CONSTRAINT_SCHEMA = 'foo'
DavidSM
источник
1
это не сработает, если ограничение на несколько столбцов. сгенерированный sql создаст отдельные ограничения для каждого столбца
загорается
Все мои FK были в одной колонке, так что я не особо задумывался об этой возможности, но хорошая мысль
DavidSM