Comment changer l'action référentielle de clé étrangère? (comportement)

102

J'ai configuré une table qui contient une colonne avec une clé étrangère, définie sur ON DELETE CASCADE(supprimer l'enfant lorsque le parent est supprimé)

Quelle serait la commande SQL pour changer cela ON DELETE RESTRICT? (impossible de supprimer le parent s'il a des enfants)

Moak
la source

Réponses:

170

Ancienne question mais ajout de réponse pour qu'on puisse obtenir de l'aide

Son processus en deux étapes:

Supposons que table1a ait une clé étrangère avec un nom de colonne fk_table2_id, avec un nom de contraintefk_name et table2soit référencé table avec clé t2( quelque chose comme ci-dessous dans mon diagramme ).

   table1 [ fk_table2_id ] --> table2 [t2]

Première étape , DROP old CONSTRAINT: ( référence )

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

la contrainte de notification est supprimée, la colonne n'est pas supprimée

Deuxième étape , AJOUTER une nouvelle CONTRAINTE:

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

ajout de contrainte, la colonne est déjà là

Exemple:

J'ai un UserDetailstableau fait référence à un Userstableau:

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

Premier pas:

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

Deuxième étape:

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)  

résultat:

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
la source
2
La contrainte que vous ajoutez ne devrait-elle pas être ON DELETE RESTRICT comme demandé par la question d'origine?
Noumenon
Ehm, qu'est-ce que "on delete cascade" et pourquoi est-ce nécessaire?
Lealo
3
@Noumenon RESTRICT est la valeur par défaut, vous obtenez cela lorsque vous ne spécifiez pas.
edruid
1
@Lealo "on delete cascade" signifie que si vous supprimez une ligne de la table parent (Users dans ce cas), toutes les lignes de référence de la table enfant (UserDetails) sont également supprimées.
edruid
1
merci pour les notes "la contrainte de notification est supprimée, la colonne n'est pas supprimée", "ajout de la contrainte, la colonne est déjà là", suppose que cela signifie que les données sont pratiquement préservées et que seul le schéma y change
George Birbilis
21

Vous pouvez le faire en une seule requête si vous souhaitez modifier son nom:

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

Ceci est utile pour minimiser les temps d'arrêt si vous avez une grande table.

Romuald Brunet
la source
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
la source
2
m'a aidé à trouver la solution ALTER TABLE table_name ADD...ON DELETE RESTRICT
Moak
3
Non, fk_name est le nom de la contrainte. Il est facultatif d'en fournir un. Je ne suis pas sûr mais peut-être que vous pouvez le récupérer en utilisant SHOW CREATE TABLE.
pascal
1
ON CASCADE RESTRICT n'est probablement pas prévu.
jgreep
5

N'oubliez pas que MySQL conserve un index simple sur une colonne après la suppression de la clé étrangère. Donc, si vous devez changer la colonne 'références', vous devez le faire en 3 étapes

  • déposer le FK original
  • déposer un index (noms comme fk précédent, drop indexclause using )
  • créer un nouveau FK
Vasiliy
la source
3

Vous pouvez simplement utiliser une seule requête pour les régler toutes: 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
la source
1
cela ne fonctionnera que si vous changez le nom de la contrainte (si vous utilisez un nom généré automatiquement, cela fonctionnera probablement, suppose que MySQL en crée toujours des uniques)
George Birbilis
La requête fonctionne à coup sûr sur MySQL / MariaDB. La clé ici est de supprimer l'ancienne contrainte par son nom, ce qui se fait à la ligne 2.
stamster
1
la syntaxe de requête tout-en-un ne fonctionnait pas pour moi avec MySQL lorsque des noms de contraintes explicites
étaient
3

J'avais un tas de FK à modifier, alors j'ai écrit quelque chose pour faire les déclarations à ma place. Je pensais que je partagerais:

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
la source
1
cela ne fonctionnera pas si une contrainte est sur plusieurs colonnes. le sql généré créera des contraintes séparées pour chaque colonne
s'allume le
Tous mes FK étaient sur des colonnes uniques, donc je ne pensais pas autant à cette possibilité, mais bonne pensée
DavidSM