web-dev-qa-db-fra.com

Bonne explication du comportement en cascade (ON DELETE / UPDATE)

Je ne conçois pas de schémas tous les jours, mais lorsque je le fais, j'essaie de configurer correctement les mises à jour/suppressions en cascade pour faciliter l'administration. Je comprends le fonctionnement des cascades, mais je ne me souviens jamais quelle table est laquelle.

Par exemple, si j'ai deux tables - Parent et Child - avec une clé étrangère sur Child qui référence Parent et a ON DELETE CASCADE, quels enregistrements déclenchent une cascade et quels enregistrements sont supprimés par la cascade? Ma première supposition serait que les enregistrements Child soient supprimés lorsque les enregistrements Parent sont supprimés, car les enregistrements Child dépendent des enregistrements Parent, mais les ON DELETE c'est ambigu; cela peut signifier supprimer l'enregistrement Parent lorsque l'enregistrement Child est supprimé, ou cela peut signifier supprimer l'enregistrement Child lorsque le Parent est supprimé. Alors c'est quoi?

Je souhaite que la syntaxe soit ON PARENT DELETE, CASCADE, ON FOREIGN DELETE, CASCADE ou quelque chose de similaire pour lever l'ambiguïté. Quelqu'un at-il des mnémoniques pour s'en souvenir?

111
Johntron

Si vous aimez les termes Parent et Child et que vous pensez qu'ils sont faciles à retenir, vous aimerez peut-être la traduction de ON DELETE CASCADE à Leave No Orphans!

Ce qui signifie que lorsqu'une ligne Parent est supprimée (supprimée), aucune ligne orpheline ne doit rester en vie dans la table Child. Tous les enfants de la ligne parent sont également tués (supprimés). Si l'un de ces enfants a des petits-enfants (dans une autre table via une autre clé étrangère) et qu'il y a ON DELETE CASCADE définis, ceux-ci doivent également être tués (et tous les descendants, tant qu'un effet de cascade est défini.)

Le FOREIGN KEY la contrainte elle-même peut également être décrite comme Allow No Orphans! (en premier lieu). Aucun Child ne doit jamais être autorisé (écrit) dans la table enfant s'il n'a pas de Parent (une ligne dans la table parent).

Par souci de cohérence, le ON DELETE RESTRICT peut être traduit en (moins agressif) You Can't Kill Parents! Seules les lignes sans enfant peuvent être supprimées (supprimées).

159
ypercubeᵀᴹ

Par exemple, si j'ai deux tables - Parent et Child - où les enregistrements Child appartiennent aux enregistrements Parent, quelle table a besoin de ON DELETE CASCADE?

ON DELETE CASCADE est une clause facultative dans une déclaration de clé étrangère. Il va donc avec la déclaration de clé étrangère. (Signification, dans le tableau "enfant".)

... cela pourrait signifier supprimer l'enregistrement parent lorsque l'enregistrement enfant est supprimé, ou cela pourrait signifier supprimer l'enregistrement enfant lorsque le parent est supprimé. Alors c'est quoi?

Une façon d'interpréter une déclaration de clé étrangère est: "Toutes les valeurs valides pour cette colonne proviennent de 'that_column' dans 'that_table'." Lorsque vous supprimez une ligne dans la table "enfant", personne ne s'en soucie. Cela n'affecte pas l'intégrité des données.

Lorsque vous supprimez une ligne de la table "parent" - de "that_table" - vous supprimez une valeur valide des valeurs possibles pour la table "enfant". Pour maintenir l'intégrité des données, vous devez faire quelque chose à la table "enfant". Les suppressions en cascade sont une chose que vous pouvez faire.


Chapitre et verset, de documents PostgreSQL .

Les suppressions restreintes et en cascade sont les deux options les plus courantes. RESTRICT empêche la suppression d'une ligne référencée. NO ACTION signifie que si des lignes de référence existent toujours lorsque la contrainte est vérifiée, une erreur est générée; c'est le comportement par défaut si vous ne spécifiez rien. (La différence essentielle entre ces deux choix est qu'aucune action ne permet de différer le chèque jusqu'à plus tard dans la transaction, contrairement à RESTRICT.) CASCADE spécifie que lorsqu'une ligne référencée est supprimée, les lignes qui la référencent doivent être automatiquement supprimées ainsi que. Il existe deux autres options: SET NULL et SET DEFAULT. Celles-ci entraînent que la ou les colonnes de référence dans la ou les lignes de référence soient définies sur null ou sur leurs valeurs par défaut, respectivement, lorsque la ligne référencée est supprimée. Notez que ceux-ci ne vous dispensent pas d'observer des contraintes. Par exemple, si une action spécifie SET DEFAULT mais que la valeur par défaut ne satisfait pas la contrainte de clé étrangère, l'opération échoue.

SQL: Spécification 2011

Il existe cinq options pour ON DELETE, et ON UPDATE qui peut s'appliquer au FOREIGN KEY. Ils sont appelés <referential actions>, directement à partir de la spécification SQL: 2011

  • ON DELETE CASCADE: si une ligne de la table référencée est supprimée, toutes les lignes correspondantes de la table référencée sont supprimées.
  • ON DELETE SET NULL: si une ligne de la table référencée est supprimée, toutes les colonnes de référence de toutes les lignes correspondantes de la table de référence doivent être définies sur null.
  • ON DELETE SET DEFAULT: si une ligne de la table référencée est supprimée, toutes les colonnes de référence de toutes les lignes correspondantes de la table de référence doivent être définies sur la valeur par défaut de la colonne.
  • ON DELETE RESTRICT: il est interdit de supprimer une ligne de la table référencée si cette ligne a des lignes correspondantes dans la table de référence.
  • ON DELETE NO ACTION(par défaut): il n'y a pas d'action de suppression référentielle; la contrainte référentielle ne spécifie qu'une vérification des contraintes.

La clé étrangère établit la relation dépendante. Le <referential action> détermine ce qui se passe lorsque la relation est dissoute.

Exemple/métaphore/explication

Pour cet exemple, nous accepterons le modèle commun de société et d'économie: où chaque business est une entreprise qui entretient une relation avec le bourgeoisie via un fatcat_owner.

CREATE TABLE bourgeoisie(
  fatcat_owner varchar(100) PRIMARY KEY
);
INSERT INTO bourgeoisie(fatcat_owner) VALUES
  ( 'Koch Brothers' );

CREATE TABLE business (
  name         varchar(100),
  fatcat_owner varchar(100) REFERENCES bourgeoisie
);
INSERT INTO business(name, fatcat_owner)
  VALUES ('Georgia-Pacific', 'Koch Brothers');

Si tous les businesses sont directement affectés par bourgeoisie par le biais de leur fatcat_owner alors que faites-vous après la révolution ouvrière quand vous purgez le fatcat_owners et avoir une société sans classes?

-- Viva la revolución 
BEGIN;
  DELETE FROM bourgeoisie;
END;

Vous avez quelques options ici,

  • Arrêtez la révolution. Dans le langage SQL, RESTRICT. Certaines personnes croient que c'est le moindre mal, mais elles ont généralement tort.
  • Laissez-le continuer. Si c'est le cas lorsque la révolution se produit, SQL vous propose quatre options,

    • SET NULL - laissez ce champ vide. Qui sait, peut-être que le capitalisme est restauré, le bourgeoisie arrive et les oligarques remplissent le rôle du fatcat_owners. Remarque importante, la colonne doit être NULLABLE (pas NOT NULL) ou cela ne peut jamais arriver.
    • SET DEFAULT - peut-être avez-vous eu un DEFAULT qui a géré cela? Un DEFAULT peut appeler une fonction. Peut-être que votre schéma est déjà prêt pour la révolution.
    • CASCADE - il n'y a pas de contrôle des dommages. Si le bourgeoisie disparaît, il en va de même du business. Si une entreprise doit avoir un fatcat_pig, alors il est parfois plus judicieux de perdre les données plutôt que d'avoir une non-entreprise dans une table business.
    • NO ACTION - c'est essentiellement une méthode pour retarder la vérification, dans MySQL ce n'est pas différent de RESTRICT, mais dans PostgreSQL, vous seriez capable de faire

      -- Not a real revolution.
      -- requires constraint be DEFERRABLE INITIALLY DEFERRED
      BEGIN;
        SET CONSTRAINTS ALL DEFERRED;
        DELETE FROM bourgeoisie;
        INSERT INTO bourgeoisie VALUES ( 'Putin' );
        UPDATE business SET fatcat_pig = 'Putin';
      END;
      

      Dans un tel système, la contrainte n'est validée qu'avant la validation de la transaction. Cela peut entraîner l'arrêt de la révolution, mais vous pouvez récupérer dans la transaction - pour un certain degré de "récupération".

4
Evan Carroll

Un simple mnémonique serait

À LA SUPPRESSION du CASCADE parent [en supprimant] ici

Cela vous indique quelles suppressions (suppressions du parent) sont mises en cascade, où l'instruction ON DELETE CASCADE va (sur l'enfant), et ce qui est supprimé ( l'enfant).

2
msouth