Différence entre On Delete Cascade et On Update Cascade dans mysql

45

J'ai deux tables dans MySQL database- parent, child. J'essaie d'ajouter des références de clé étrangère à ma table enfant en fonction de la table parent. Existe-t-il une différence significative entre ON UPDATE CASCADEetON DELETE CASCADE

Ma table des parents

CREATE TABLE parent (
    id INT NOT NULL,
    PRIMARY KEY (id)
) ENGINE=INNODB;

Ma question est la suivante: quelle est la différence entre les requêtes SQL suivantes?

  1. ON DELETE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON DELETE CASCADE
    ) ENGINE=INNODB;
  2. ON UPDATE CASCADE

    CREATE TABLE child (
        id INT, 
        parent_id INT,
        INDEX par_ind (parent_id),
        FOREIGN KEY (parent_id) 
            REFERENCES parent(id)
            ON UPDATE CASCADE
    ) ENGINE=INNODB;
  3. ON UPDATE CASCADE ON DELETE CASCADE

    CREATE TABLE child (
            id INT, 
            parent_id INT,
            INDEX par_ind (parent_id),
            FOREIGN KEY (parent_id) 
                REFERENCES parent(id)
                ON UPDATE CASCADE ON DELETE CASCADE
        ) ENGINE=INNODB;

Y a-t-il des erreurs dans les requêtes? Que signifient ces requêtes (1,2 et 3)? Sont-ils les mêmes ???

Loup solitaire
la source
1
ps <nitpick> pour être complet, ce dont vous parlez ci-dessus sont des instructions DDL (Data Definition Language) et non des requêtes. Une requête est généralement considérée comme une requête DML (langage de manipulation de données SELECT, INSERT, UPDATE, DELETE) </ nitpick>
Vérace
Encore un autre ps pour être complet, je me suis demandé quelle était la valeur par défaut. J'ai donc créé un enfant sans mise à jour ni suppression. Ce qui se passe alors, c'est que vous ne pouvez ni mettre à jour ni supprimer un parent ayant un enfant à charge. Cela a du sens, cependant, MySQL n’est pas toujours un modèle de cette caractéristique particulière :-)
Vérace

Réponses:

64

Un très bon fil sur ce sujet se trouve ici et aussi ici . Le guide définitif pour MySQL est, bien sûr, la documentation, à retrouver ici .

Dans le standard SQL 2003, il existe 5 actions référentielles différentes:

  1. CASCADE
  2. RESTREINDRE
  3. PAS D'ACTION
  4. SET NULL
  5. DÉFINIR PAR DEFAUT

Pour répondre à la question:

  1. CASCADE

    • ON DELETE CASCADEsignifie que si l'enregistrement parent est supprimé, tous les enregistrements enfants sont également supprimés. Ce n'est pas une bonne idée à mon avis. Vous devez garder une trace de toutes les données qui ont déjà été dans une base de données, bien que cela puisse être fait en utilisant TRIGGERs. (Cependant, voir la mise en garde dans les commentaires ci-dessous).

    • ON UPDATE CASCADECela signifie que si la clé primaire parent est modifiée, la valeur enfant changera également pour refléter cela. Encore une fois à mon avis, pas une bonne idée. Si vous changez PRIMARY KEYde façon régulière (ou même pas du tout!), Il y a un problème avec votre conception. Encore une fois, voir les commentaires.

    • ON UPDATE CASCADE ON DELETE CASCADEsignifie que si vous UPDATE OU DELETE le parent, le changement est répercuté sur l'enfant. C'est l'équivalent des ANDrésultats des deux premières déclarations.

  2. RESTREINDRE

    • RESTRICTsignifie que toute tentative de suppression et / ou de mise à jour du parent échouera. C'est le comportement par défaut dans le cas où une action référentielle n'est pas explicitement spécifiée.

      Pour un ON DELETEou ON UPDATEqui n'est pas spécifié, l'action par défaut est toujours RESTRICT`.

  3. PAS D'ACTION

    • NO ACTION: Du manuel . Un mot clé de SQL standard. En MySQL, équivalent à RESTRICT. Le serveur MySQL rejette l'opération de suppression ou de mise à jour de la table parent s'il existe une valeur de clé étrangère liée dans la table référencée. Certains systèmes de base de données ont des contrôles différés et il NO ACTIONs’agit d’un contrôle différé. Dans MySQL, les contraintes de clé étrangère sont vérifiées immédiatement, donc NO ACTIONest identique à RESTRICT.
  4. SET NULL

    • SET NULL- encore du manuel. 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. Ce n’est pas la meilleure des idées à mon humble avis, principalement parce qu’il n’ya aucun moyen de «voyager dans le temps» - c’est-à-dire regarder dans les tables enfants et associer des enregistrements à NULLs avec l’enregistrement parent correspondant - CASCADEou utiliser TRIGGERs pour remplir les tables de journalisation afin de suivre changements (mais, voir les commentaires).
  5. DÉFINIR PAR DEFAUT

    • SET DEFAULT. Encore une autre partie (potentiellement très utile) du standard SQL que MySQL n’a pas pris la peine de mettre en œuvre! Permet au développeur de spécifier une valeur sur laquelle définir la ou les colonnes de clé étrangère sur un UPDATE ou un DELETE. InnoDB et NDB rejetteront les définitions de table avec une SET DEFAULTclause.

Comme mentionné ci-dessus, vous devriez passer un peu de temps à regarder la documentation, ici .

Vérace
la source
8
J'aime votre réponse complète mais je ne suis pas d'accord avec cette affirmation. "Vous devez garder une trace de toutes les données qui ont jamais été dans une base de données" - cela dépend vraiment de la conception et des objectifs de la base de données. Par exemple, une définition de recette (je ne parle pas de nourriture - plutôt de configurations de systèmes) lorsque la définition de recette est supprimée, cela n'a aucun sens de garder les enfants associés à cette recette - qui ne font que gonfler la base de données sans raison. Tables de travail pour systèmes de machines également - je n’ai plus besoin des données; processus et se débarrasser de lui. Sinon, votre réponse est fantastique.
StixO
2
similaire à @StixO J'aime cette réponse surtout, mais je ne suis pas d'accord avec le changement de clé primaire. Il existe certainement des conceptions dans lesquelles ce serait une mauvaise idée, mais lorsque vous accédez à une base de données distribuée, il peut être très souhaitable que les clés primaires puissent être réaffectées sans perdre l'identité d'un enregistrement.
Garet Claborn
"Ce n'est pas une bonne idée à mon avis. Vous devriez garder une trace de toutes les données qui ont déjà été dans une base de données." - Je ne suis pas sûr de comprendre votre argument. Si vous mettez en cascade 'on delete', vous avez déjà décidé de supprimer quelque chose. Si vous décidez de ne jamais supprimer quoi que ce soit, rien ne sera en cascade. L’avantage de l’avoir, c’est que dans votre application, vous pouvez être sûr que lorsque vous rechercherez un enregistrement avec une ID étrangère, vous saurez qu’il sera là et qu’il n’y aura pas de rangs orphelins gonflant votre base de données si vous décidez de le supprimer. quelque chose.
Jeff Ryan
La logique ici est assez défaillante par endroits, et plus encore dans notre nouveau monde GDPR. Je suis d'accord avec l'idée que si les clés primaires changent, cela pourrait être le signe d'un problème.
Chuck Le Butt le
Si vous modifiez les clés PRIMARY avec une quelconque régularité (ou même du tout!), Il y a un problème avec votre conception. Voulez-vous dire ON UPDATE CASCADE modifie la valeur de la clé ou le nom de la clé?
Billal Begueradj
8

Ces deux actions sont à effectuer, respectivement, lorsque l’enregistrement référencé sur la table parent change d’identifiant et lorsqu’il est supprimé.

Si vous exécutez:

UPDATE parent SET id = -1 WHERE id = 1;

Et il y a au moins un enregistrement childavec parent_id = 1, 1) échouera; dans les cas 2) et 3), tous les enregistrements avec parent_id = 1 sont mis à jour pour parent_id = -1.

Si vous exécutez:

DELETE FROM parent WHERE id = 1;

Et il y a au moins un enregistrement childavec parent_id = 1, 2) échouera; dans les cas 1) et 3), tous les enregistrements avec parent_id = 1sont supprimés.

3) est syntaxiquement correct.

Une documentation complète est disponible sur le manuel .

Jynus
la source
6

Je n'ai pas assez de réputation pour commenter les réponses précédentes. Alors j'ai pensé élaborer un peu.

1) ON DELETE CASCADE signifie que si l'enregistrement parent est supprimé, tous les enregistrements enfants référençant sont également supprimés. ON UPDATE a pour valeur RESTRICT, ce qui signifie que UPDATE sur l'enregistrement parent échouera.

2) L'action ON DELETE est définie par défaut sur RESTRICT, ce qui signifie que la suppression de l'enregistrement parent échouera. ON UPDATE CASCADE mettra à jour tous les enregistrements enfants référençant lors de la mise à jour de l'enregistrement parent.

3) Voir les actions CASCADE en 1) et 2) ci-dessus.

Utilisation des ID d’enregistrement parent comme clés étrangères (dans les tables enfants) - l’expérience dit a) si les ID sont des numéros de séquence générés automatiquement, NE les utilisez PAS en tant que clés étrangères. Utilisez plutôt une autre clé parent unique. b) si les ID sont des GUID, vous pouvez les utiliser comme clés étrangères. Vous verrez l'intérêt de cette suggestion lorsque vous exportez et importez les enregistrements ou que vous les copiez dans une autre base de données. Il est trop fastidieux de traiter des numéros de séquence générés automatiquement lors de la migration de données lorsqu'ils sont référencés en tant que clés étrangères.

gr
la source