Como alterar a ação referencial da chave estrangeira? (comportamento)

102

Eu configurei uma tabela que contém uma coluna com uma chave estrangeira, definida como ON DELETE CASCADE(excluir filho quando o pai for excluído)

Qual seria o comando SQL para alterar isso ON DELETE RESTRICT? (não é possível excluir o pai se houver filhos)

Moak
fonte

Respostas:

170

Pergunta antiga, mas adicionando resposta para que se possa obter ajuda

Seu processo de duas etapas:

Suponha que a table1tenha uma chave estrangeira com nome de coluna fk_table2_id, com nome de restriçãofk_name e table2seja referida como tabela com chave t2( algo como a seguir em meu diagrama ).

   table1 [ fk_table2_id ] --> table2 [t2]

Primeiro passo , DROP old CONSTRAINT: ( referência )

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

observe que a restrição foi excluída, a coluna não foi excluída

Segunda etapa , ADICIONE nova CONSTRAINT:

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

adicionando restrição, a coluna já está lá

Exemplo:

Eu tenho uma UserDetailstabela que se refere à Userstabela:

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`)
:
:

Primeiro passo:

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

Segundo passo:

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)  

resultado:

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
:
Grijesh Chauhan
fonte
2
A restrição adicionada não deveria ser ON DELETE RESTRICT, conforme solicitado pela pergunta original?
Noumenon
Ehm, o que é "on delete cascade" e por que isso é necessário?
Lealo
3
@Noumenon RESTRICT é o padrão, então você obtém isso quando não especifica.
edruid
1
@Lealo "na exclusão em cascata" significa que se você excluir uma linha da tabela pai (Usuários neste caso), todas as linhas de referência da tabela filho (UserDetails) também serão excluídas.
edruid
1
obrigado pelas notas "observe que a restrição foi excluída, coluna não foi excluída", "adicionando restrição, a coluna já está lá", acho que isso significa que os dados estão praticamente preservados e apenas o esquema muda lá
George Birbilis
21

Você pode fazer isso em uma consulta se desejar alterar seu nome:

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

Isso é útil para minimizar o tempo de inatividade se você tiver uma mesa grande.

Romuald Brunet
fonte
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;
pascal
fonte
2
me ajudou a encontrar a solução ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak
3
Não, fk_name é o nome da restrição. É opcional fornecer um. Não tenho certeza, mas talvez você possa recuperá-lo usando SHOW CREATE TABLE.
pascal
1
ON CASCADE RESTRICT provavelmente não se destina.
jgreep
5

Lembre-se de que o MySQL mantém um índice simples em uma coluna após excluir a chave estrangeira. Portanto, se você precisar alterar a coluna de 'referências', deverá fazê-lo em 3 etapas

  • solte o FK original
  • descartar um índice (nomes como fk anterior, drop indexcláusula using )
  • criar novo FK
Vasiliy
fonte
3

Você pode simplesmente usar uma consulta para controlar todos eles: 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

stamster
fonte
1
isso funcionará apenas se você alterar o nome da restrição (se estiver usando um nome gerado automaticamente, provavelmente funcionará, acho que o MySQL sempre cria nomes únicos)
George Birbilis
A consulta funciona com certeza no MySQL / MariaDB. A chave aqui é eliminar a restrição antiga pelo nome, o que está sendo feito na linha 2.
stamster
1
A sintaxe de consulta multifuncional não funcionou para mim com MySQL quando nomes de restrição explícitos foram usados
George Birbilis
3

Eu tinha um monte de FKs para alterar, então escrevi algo para fazer as declarações para mim. Imaginei que compartilharia:

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
fonte
1
isso não funcionará se houver uma restrição em várias colunas. o sql gerado criará restrições separadas para cada coluna
luzes de
Todos os meus FKs estavam em colunas únicas, então eu não estava pensando muito sobre essa possibilidade, mas boa ideia
DavidSM