Trigger SQL avant suppression

Fermé
minimatt - 2 juil. 2010 à 15:24
 minimatt - 3 juil. 2010 à 17:58
Bonjour,

Je travaille actuellement sur un projet utilisant une base de données MySQL 5.0.41, et à cause de son rôle plutôt critique et du nombre de tables liées entre elles, je souhaiterais ajouter des contraintes d'intégrité référentielles. Malheureusement, c'est la première fois que je touche à ces bidules...

Disons que j'ai une table A contenant un ID et un nom, et une table B faisant référence à la table A pour désigner la personne concernée.

+----------- A -----------+   +----------- B -----------+
| id        smallint(3)   |   | ...       ............  |
| name      varchar(255)  |   | who       smallint(3)   |
+-------------------------+   | ...       ............  |
                              +-------------------------+

Maintenant, je voudrais qu'un enregistrement de la table A ne puisse être supprimé s'il en existe des références dans la table A, histoire de ne pas me retrouver avec un enregistrement en B faisant référence à quelqu'un qui n'existe plus.... Après plusieurs heures de recherches et d'essais, je me retrouve là :

CREATE TRIGGER a_before_delete BEFORE DELETE ON A FOR EACH ROW
BEGIN

IF EXISTS (SELECT * FROM B WHERE who = old.id)
BEGIN
RAISERROR ('Impossible de supprimer une personne encore référencée');
ROLLBACK TRANSACTION;
END;

END;

Malheureusement, ma syntaxe n'est pas bonne dans le.... if ?!
Un coup de main, s'y'ouplait ? C'est vraiment important ='(

4 réponses

blux Messages postés 26532 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 18 décembre 2024 3 317
2 juil. 2010 à 15:52
Salut,

en principe, une fois que l'on a mis une contrainte d'intégrité référentielle, pas besoin de trigger, c'est le SGBD lui-même qui va te dire qu'il reste des records dans B et que tu ne peux supprimer A.
0
Ohoh... Donc ça ne marche pas vraiment comme je croyais....
Dans ce cas, disons que je préfère les triggers aux contraintes, histoire de pouvoir insérer dans une table log les éventuelles erreurs (ça, j'y arrive déjà ='P). Quelle est l'erreur de syntaxe dans mon bout de code ?
0
blux Messages postés 26532 Date d'inscription dimanche 26 août 2001 Statut Modérateur Dernière intervention 18 décembre 2024 3 317
2 juil. 2010 à 16:24
Quelle est l'erreur de syntaxe dans mon bout de code ?
Aucune idée...
0
Salut

je ne suis pas très versé dans MySQL, je viens juste te filer une ou deux pistes à explorer.

1. la gestion de la transaction : ce n'est pas à un trigger de valider ou d'invalider une transaction. ton trigger doit se contenter de lever une exception, rien de plus
2. au lieu de tester l'existence de x lignes de y colonnes dans le if, je conseillerais plutôt
a. affecter select count(1) from B where who = old.id à une variable
b. vérifier si la variable est différente de 0 => exception

en règle générale, il faut éviter de lire des données dont on n'a pas besoin. ici, tu lis toutes les colonnes des x lignes de B en correspondance avec ton id supprimé alors qu'en fait seul le nombre de lignes t'intéresse :-(

3. (ça c'est bonus) certes, tu log tes erreurs, mais le système sera toujours infiniment plus rapide que le plus optimisé de tes codes => sers-toi donc de l'intégrité référentielle comme te l'a conseillé blux
0
Effectivement, je suis pas du tout au point niveau optimisation =')
Malheureusement, même avec une contrainte d'intégrité référentielle, je n'y arrive pas ! J'arrive bien à ajouter la contrainte sur la table B, mais je peux tout de même ajouter des enregistrements dans ladite table qui ne correspondent à aucun ID de la table A, ou même supprimer un enregistrement de la table A auquel sont reliés des enregistrements de B...... La requête ajoutant la contrainte est pourtant bien exécutée :

ALTER TABLE B ADD CONSTRAINT who_a_id FOREIGN KEY (who) REFERENCES A(id);
Qu'est-ce que j'oublie ?
0
Salut,

J'ai retrouvé un vieux MySQL (Ver 14.12 Distrib 5.0.19 for Win32) où j'ai pu tester quelques bricoles... il en ressort que (à l'instar d'autres SGBD) la contrainte ne s'applique pas pour une valeur NULL ; par contre, une valeur non trouvée dans la colonne référencée sera rejetée. même sanction pour la suppression de la ligne référencée.

donc, essaie d'ajouter une contrainte NOT NULL sur la colonne who pour voir si tu n'atteindrais pas enfin le fonctionnement désiré.
0
Le champ who est déjà en NOT NULL.
J'ai essayé de tout faire en ligne de commande, au cas où ce soit phpMyAdmin qui n'aime pas trop ces clés (il les affiche comme des clés "Index"), mais ça n'a rien changé... Help !! :-'(
0
Le problème vient apparamment du moteur que j'utilise, qui ne supporte pas les FOREIGN KEYs. Je vais vérifier, mais à priori c'est la seule explication.
0
Je confirme, le problème vient bien de mon moteur de stockage. J'utilise actuellement MyISAM, qui ne supporte pas les clés étrangères... Bon, erreur de débutant, mais heureusement la solution est simple.

ALTER TABLE '...' ENGINE = INNODB
J'espère que cela pourra aider quelqu'un =/
0