Trigger insertion

[Résolu/Fermé]
Signaler
-
 Yestt -
Bonjour,

Je dois faire un exercice pour lundi et qui sera noté, pourriez vous m'aider. Le voici.

Soit la table ADHERENT(numAdherent,nom,CP,numCAdherent) présente dans la Base de données d'une bibliothèque. L'attribut numCAdherent peut être NULL. Ecrire un trigger en insertion permettant de contrôler les contraintes suivantes :
- le code postal dans lequel habite l'adhérent doit être 01,05 ou 70.
- si numCAdherent est différent de NULL, le nom du conjoint de l'Adhérent doit être le même que celui de l'adhérent.

Créer le trigger nommé INSESERADHERENT avec l'ordre qui suit :

CREATE TRIGGER INSERERADHERENT
BEFORE INSERT ON ADHERENT
FOR EACH ROW
DECLARE
-- saisir votre code
BEGIN
IF CP=01 OR CP=05 OR CP=70 then
INSERT INTO ADHERENT SET CP="....", numAdherent=' ..' ,nom=' ...' , numCAdherent=' '
ELSE
RAISE_APPLICATION_ERROR( - 20003,'CP non valide!!!!');
END IF;
EXCEPTION
--saisir votre code
END;

Est ce que le premier test est correct ? Par contre, je ne sais pas trop quoi mettre dans le INSERT...
Merci d'avance pour votre réponse.
Yestt

9 réponses

Messages postés
118
Date d'inscription
mercredi 9 décembre 2009
Statut
Membre
Dernière intervention
10 décembre 2018
14
Bon sans rentrer dans les détails, il y a une chose qui me gène, c'est que tu fais l'insert déjà ça c'est une grosse bêtise qui me saute aux yeux !
Faut bien comprendre qu'un trigger c'est comment dire, comme une fonction que tu branche sur un évènement .... Quand tu déclares CREATE TRIGGER <nom> BEFORE INSERT ON <table>, tu définis très clairement que tu veux que le système de base de données appelle ta procédure lorsque l'évènement déclanché juste avant une insertion sur la table spécifié ! Autrement dit, tu peux tout à fait créer plusieur trigger sur le même évènement de la même table !
Imagine donc le cas ou tu mettes deux triggers dessus du même genre, ça ferait 2 fois l'insertion plus une dernière fois avec l'insertion initiale qui a délanchée les deux triggers ! Tu comprends ?
Donc on ne fait pas l'insertion dans le trigger ...

Attention, j'ai pas dit que t'avais pas le droit de faire des INSERT dans la procédure ...
Mais l'insertion initiale se suffit à elle même !

Donc première remarque, ton test sur les codes postaux ne doit servir que s'il est non vérifié, la seulement tu fait ton RAISE_ERROR() ... sinon tu continue ...

Reste plus que ton deuxième test ...
L'énoncé dit que si numCAdherent est non null, il faut que la personne ai le même nom que le conjoint.
T'as juste à récupérer le nom de la personne qui à l'id du conjoint comme id ... et prendre son nom et écraser la valeur du nom en cours par celui là ...
Un truc du genre :
SELECT nom_a_inséré = nom WHERE numAdherent = le numCAdherent_a_inséré

Le reste c'est qu'une histoire de syntaxe !
Pourvu que t'ai compris...
J'avais pourtant dit que je te ferais pas ton exo...
Ok merci bien. Donc si j'ai bien compris,cela donne :
CREATE TRIGGER INSERERADHERENT
BEFORE INSERT ON ADHERENT
FOR EACH ROW
DECLARE
nomConjoint VARCHAR;
numCAdherent NUMBER;
BEGIN
IF NOT (CP=01 OR CP=05 OR CP=70)then
RAISE_APPLICATION_ERROR( - 20003,'CP non valide!!!!');
END IF;
IF numCAdherent IS NOT NULL THEN
:old.nomConjoint = :new.nom WHERE :old.numCAdherent =:new.numAdherent:
END IF;
EXCEPTION
--saisir votre code
END;

Est ce quelque chose de genre ?
Messages postés
118
Date d'inscription
mercredi 9 décembre 2009
Statut
Membre
Dernière intervention
10 décembre 2018
14
A mon avis oui, c'est ça ...
Cela dit je connais pas tout à fait cette syntaxe (MySql ? Oracle ? Postgresql ?) mais d'un point de vue algo c'est bon pour moi ! ;)
Salut

Ça ressemble à de l'oracle.

J'ai plus pratiqué le PL/SQL depuis Oracle 7. Mais je pense pas que
IF numCAdherent IS NOT NULL THEN
:old.nomConjoint = :new.nom WHERE :old.numCAdherent =:new.numAdherent:
END IF;
soit bien valide même en Oracle 11 !?
Car il n'est pas utilisé d'affectation (:=) et l'utilisation de WHERE comme un diablotin sorti de sa boite me semble inadéquate. Qui plus est, l'utilisation de l'alias old est erroné dans un trigger avant insertion

rappel: la ligne déclenchant le trigger est disponible sous forme de l'alias :old pour offrir ses valeurs avant suppression ou modification et sous forme de l'alias :new pour offrir ses valeurs avant insertion ou modification.

Donc, si l'on avait été dans un trigger avant modification, nous aurions pu écrire
IF numCAdherent IS NOT NULL AND :old.numCAdherent = :new.numAdherent THEN
  :new.nom := :old.nomConjoint
END IF;
Mais j'aime pas trop ce genre de code, je préfère que le client lui-même choisisse ce qu'il faut mettre en nom

Je n'ai jamais utilisé les triggers "before" que pour vérifier la cohérence de ce qui est proposé avec les différentes règles dictant le fonctionnement de la base => le refus de la ligne est traduit par une exception (cf l'exception déclenchée pour code postal non géré). Ce fonctionnement permet de rejeter la transaction AVANT l'enregistrement des données dans la base (on n'aura pas à faire un rollback consommateur en temps)
D'un autre côté, le trigger "after" devrait servir à répercuter là mises à jour dans la base (ie alimenter une table de synthèse ou appeler une procédure qui dispatche la nouvelle info) mais surtout pas à déclencher une exception

En dernier lieu, Oracle 10g Express Edition est librement utilisable (car limitée à 4Go data, 1Go Ram et 1 cœur) donc, pour peu que ta machine n'ait pas plus de trois ans, tu peux tester tes triggers et procédures à la maison
Ok merci beaucoup pour vos explications. Oui je travaille à l'université avec Oracle (je ne sais pas quelle version).
Donc il vaudrait mieux mettre :
IF numCAdherent IS NOT NULL AND :old.numCAdherent = :new.numAdherent THEN
:new.nom := :old.nomConjoint
END IF;

C'est celà pour cette condition :
si numCAdherent est différent de NULL, le nom du conjoint de l'Adhérent doit être le même que celui de l'adhérent. ?
Sinon concernant le CP le test est bon ?
Merci beaucoup.
non ! non ! et non !

le si teste une condition. si elle est remplie les intructions entre THEN et ELSE (ou THEN et END IF) sont exécutées. donc ici, on affecte l'ancien nomConjoint au nouveau nom

mais je ne m'étais attaché qu'à un passage du post 5 : le IF où tout est mélangé.
pour faire plus propre, j'ai survolé le topic en entier.

1. le test sur le CP: je ne m'y étais pas attardé. Et même si Oracle est assez souvent surprenant, j'ai tendance à ne pratiquer que ce qui est connu. donc pour moi ce serait IF (CP!=1) AND (CP!=5) AND (CP!=70) ou mieux IF CP NOT IN (1, 5, 70) car le NOT (condition1 OR condition2 OR condition3) j'y crois pas trop (mais ça se teste!)

2. pour ton égalité sur le nom du conjoint, il faudrait plutôt
IF numCAdherent is not null 
  IF nomAdherent <> nomCAdherent THEN
    raise_application_error(-20004, 'Patronyme du conjoint différent'):
  END IF
END IF;
Mais ça implique que le numéro d'adhérent du conjoint ainsi que son nom soit dispos dans la ligne de données de l'adhérent.

3. Comme ton trigger concerne une insertion, je te confirme qu'il n'y a pas une ligne alias :old disponible dans le trigger. tout doit être dans :new
Ok merci beaucoup pour vos explications. Je pense avoir compris en partie. Pour répondre à Cephei, j'utilise bien le langage PL/SQL. Sinon donc cela donne :

CREATE TRIGGER INSERERADHERENT
BEFORE INSERT ON ADHERENT
FOR EACH ROW
DECLARE
nomCAdherent VARCHAR;
BEGIN
IF CP NOT IN (1, 5, 70) THEN
RAISE_APPLICATION_ERROR( - 20003,'CP non valide!!!!');
END IF;
IF numCAdherent is not null
IF nomAdherent <> nomCAdherent THEN
raise_application_error(-20004, 'Patronyme du conjoint différent'):
END IF
END IF;
EXCEPTION
END;

L'attribut numCAdherent est bien présent dans la base. Par contre nomCAdherent n'est pas présent, donc est ce correct de le déclarer en haut du trigger et de l'utiliser ensuite ou faut il le sélectionner ailleurs.
Un ami m'a indiqué qu'il valait mieux mettre :new.cp mais je ne sais pas si çà change quelque chose...
Merci pour vos explications.
Messages postés
118
Date d'inscription
mercredi 9 décembre 2009
Statut
Membre
Dernière intervention
10 décembre 2018
14
T'enerve pas flu ...
C'était surtout pour le principe ! Comme je te l'ai dit, je ne sais toujours pas le language utilisé ...

Deuxièmement, pour le nom du conjoint je te rapelle que la donnée n'existe pas directement dans les donnée de l'insertion, c'est qu'un id qui est renseigné ou non ...
Il faut donc bien faire un select avec cet id pour récupérer le nom du conjoint ! Et l'énoncé dit bien : "si numCAdherent est différent de NULL, le nom du conjoint de l'Adhérent doit être le même que celui de l'adhérent"
Tu peux faire un test dégalité avant si ça t'amuse mais c'est même pas la peine puisque de toute façon tu dois faire le select pour récupérer la donnée ! Autant faire l'affectation sans faire le test d'égalité une fois la donnée récupérée !

Pour le reste, vu qu'il semble que tu est reconnu que se soit du PL/SQL, tu dois surment avoir raison ... Ca fait presque une dixaine d'année que j'ai pas fait de PL/SQL !
Trop fiu pour être énervé :-)

Comme c'est un exercice, je ne me prononcerai pas sur la récupération du second patronyme, le prof a peut-être envie d'une belle introduction pour présenter l'intérêt des procédures quand quelques fois on tombe sur qqe chose d'infaisable par trigger

par contre, je me contenterai de signaler à Yestt qu'il ne peut laisser son bloc exception tel quel : soit on gère l'exception soit on la gère pas. Et dans le cas du trigger, mieux vaut ne rien gérer (on est DANS la base) et laisser le soin de cette gestion à une couche supérieure, idéalement l'applicatif
Ok merci. Je dois le rendre demain et le stress est au maximu. Je peux le laisser comme celà ou je dois faire autre chose ?
Salut Yestt.

Faut pas stresser, c'est mauvais pour le vieillissement cellulaire.
Faut juste se sentir capable d'expliquer tout ce que fait ton œuvre.
Donc être capable de te mettre à la place de ton prof qui va te demander à quoi sert ceci ou pourquoi tu as mis cela.
Et une question qu'il ne risque pas d'oublier c'est : "tu compares nomAdherent avec nomCAdherent. mais qu'y a-t-il dans nomCAdherent ?" Et là, tu relis vite fait ton trigger et tu te rends compte que tu l'as bien déclaré mais qu'aucune valeur n'y a été stockée. Donc que tu compares nomAdherent à rien (ou n'importe quoi, je sais plus).

Donc, il vient d'où ton nomCAdherent ? il est bien présent quelque part si tu veux le comparer à nomAdherent !
Bonsoir,
C'est bien mon problème mais je ne sais pas comment le récupérer car il 'est pas dans ma table ADHERENT... Faut-il que j'affecte une valeur au hazard ou faire un select sur une autre table... Qu'en pensez vous ?
Merci d'avance.
> Yestt
Bon c'est fini. Merci quand même. Bonne journée.
Messages postés
118
Date d'inscription
mercredi 9 décembre 2009
Statut
Membre
Dernière intervention
10 décembre 2018
14
Bonsoir,

Comme tu l'as très bien dit toi même : JE dois faire un exercice pour lundi ...
Donc bon courage, relis tes cours c'est forcément dedans et pis si t'as un doute, tu tests !
Bonsoir,
Malheureusement, je ne peux pas tester chez moi... Pourriez juste me dire si le début est bon ?
Messages postés
118
Date d'inscription
mercredi 9 décembre 2009
Statut
Membre
Dernière intervention
10 décembre 2018
14
Ok bon j'veux bien t'aider mais c'est hors de question que je te le fasse ...
Ca me gonfle ça, si vous faite ça en cours c'est pas pour que d'autre types comme moi sur le net vous fasse vos exos (t'es pas le premier, c'est pour ça c'est vite énervant !)...

Mais une question d'abord c'est censé être du Transac Sql (MSSQL) ou du MySql ?