Dans la structure de la base de données de
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;
Je m'attends à supprimer le parent de City
en laissant la valeur correspondante dans child intacte par ces trois commandes égales
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)
Mais lorsque vous utilisez NO ACTION
OR RESTRICT
ou en omettant ON DELETE
. MySQL ne me permet pas de supprimer de la colonne parent avec cette erreur:
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
Où ai-je tort? N'est-ce pas la responsabilité du NO ACTION
pour supprimer le parent et laisser l'enfant orphelin?
Selon la Documentation MySQL sur DELETE RESTRICT
• RESTRICT: rejette l'opération de suppression ou de mise à jour de la table parent. Spécifier RESTRICT (ou NO ACTION) revient à omettre la clause ON DELETE ou ON UPDATE.
Quant à AUCUNE ACTION
• PAS D'ACTION: mot-clé de SQL standard. Dans MySQL, équivalent à RESTRICT. InnoDB rejette l'opération de suppression ou de mise à jour de la table parent s'il existe une valeur de clé étrangère associée dans la table référencée. Certains systèmes de base de données ont des vérifications différées et NO ACTION est une vérification différée. Dans MySQL, les contraintes de clé étrangère sont vérifiées immédiatement, donc NO ACTION est identique à RESTRICT.
DELETE RESTRICT protège le parent de la suppression, pas les enfants.
Si vous voulez supprimer le parent et laisser l'enfant, alors vous voulez probablement le ON DELETE SET NULL
option:
SET NULL: supprimez ou mettez à jour la ligne de la table parent et définissez la ou les colonnes de clé étrangère de la table enfant sur NULL. Les clauses ON DELETE SET NULL et ON UPDATE SET NULL sont prises en charge.
Si vous spécifiez une action SET NULL, assurez-vous que vous n'avez pas déclaré les colonnes de la table enfant comme NOT NULL.
Il y a beaucoup de "non" dans cette dernière phrase, alors assurez-vous simplement que le parent_id peut être NULL.
Voir aussi cette question connexe: Quel est le but de SET NULL dans les contraintes Delete/Update Foreign Keys?
En définissant une clé étrangère, vous avez dit à la base de données de ne pas accepter les entrées de la table enfant qui n'ont pas de valeur correspondante dans le parent.