PostgreSQL La base de donnees la plus sophistiquee au monde.

Forums PostgreSQL.fr

Le forum officiel de la communauté francophone de PostgreSQL

Vous n'êtes pas identifié(e).

#1 21/12/2016 00:43:42

PunkAndBad
Membre

Problème de cohabitation de triggers

Bonjour à vous toutes et tous,


Étant débutant sous PostgreSQL, je bloque depuis plusieurs jours sur un trigger.


J'ai 3 tables :


COMMANDES
PrK - ID_COMMANDE (auto_inc)
FrK - ID_CARTON    (int)
-----------------------------------------------------
CARTONS
Prk - ID_CARTON (auto_inc)
NUM_CARTON        (int)
QTE_OBJET_CARTON (int)
QTE_OBJET_RESTANT_CARTON  (int)
NUM_SERIE_DEBUT        (int)
NUM_SERIE_FIN        (int)
-----------------------------------------------------
OBJETS
PrK - ID_OBJET   (auto_inc)
NUM_SERIE_OBJET  (int)
ACTIF_OBJET       (bool)


Le 1er trigger (tables CARTONS) :


CREATE OR REPLACE FUNCTION cartons_sortie() RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO COMMANDES (ID_CARTON) (SELECT ID_CARTON FROM CARTONS WHERE QTE_OBJET_RESTANT_CARTON = NEW.QTE_OBJET_RESTANT_CARTON);
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;


create trigger sortie_cartons
after update on cartons
for each row
    execute procedure cartons_sortie();


Lorsque je modifie manuellement dans la table CARTONS les valeurs du champ QTE_OBJET_RESTANT_CARTON, les ID_CARTON associés
s'insèrent correctement dans la table COMMANDES.

Le 2nd trigger (tables OBJETS) :


CREATE OR REPLACE FUNCTION Compte_Objets_Actif() RETURNS TRIGGER AS $$
BEGIN
update cartons car
set QTE_OBJET_RESTANT_CARTON = (select count(actif_objet) from objets objt
                                   where actif_objet = TRUE
                                   and car.id_carton = objt.id_carton);

    RETURN new;
END;
$$ language plpgsql;


CREATE TRIGGER Objets_Compte_Actif
AFTER UPDATE ON objets
FOR EACH ROW
  EXECUTE PROCEDURE Compte_Objets_Actif();

 
Lorsque dans la table OBJETS je passe le champ ACTIF_OBJET de TRUE à FALSE, le champ QTE_OBJET_RESTANT_CARTON de la table CARTONS se recalcule automatiquement m'indiquant ainsi les objets restants pour chaque carton (ID_CARTON).


Séparement ces 2 triggers fonctionnent parfaitement, par contre lorsqu'ils cohabitent PostgreSQL me retourne une erreur en indiquant qu'il y a une duplication de clés dans la table COMMANDES.


Je suis débutant sous PostgreSQL mais je pense comprendre que lorsque les champs ACTIF_OBJET passent à FALSE (table OBJETS), le 2nd trigger recalcule sans distinction tous les champs QTE_OBJET_RESTANT_CARTON de la table CARTONS. Le 1er trigger s'enclenche alors et tous les ID_CARTON vont essayer de s'insérer dans la table COMMANDES provoquant ainsi une erreur.


J'ai beau modifier mon 2nd trigger je retombe toujours sur ce problème de duplication de clés.
Si vous avez une idée ou une solution je suis preneur.


Merci à vous.

@+

Hors ligne

#2 21/12/2016 10:43:32

Marc Cousin
Membre

Re : Problème de cohabitation de triggers

Bonjour,

Le mieux, c'est de rajouter une petite trace dans chaque fonction de trigger pour voir ce qu'elles font. Faites le avec RAISE. Par exemple dans le premier trigger:

RAISE NOTICE 'appel du trigger Compte_Objets_Actif pour %',new.QTE_OBJET_RESTANT_CARTON

C'est évidemment un exemple très basique, c'est juste pour vous montrer la syntaxe.

Hors ligne

#3 21/12/2016 23:40:29

PunkAndBad
Membre

Re : Problème de cohabitation de triggers

Merci pour votre réponse M. COUSIN.

Il y avait un petit oubli dans la table OBJETS. J'ai oublié la clé étrangère ID_CARTON.

La table est constituée de la manière suivante :

OBJETS
PrK - ID_OBJET   (auto_inc)
NUM_SERIE_OBJET  (int)
ACTIF_OBJET       (bool)
FrK - ID_CARTON (int)


J'ai rajouté votre "exemple" dans les trigger mais je ne vois pas de traces de sortie du RAISE NOTICE dans la console de PgAdmin 4 ni dans le fichier pg_log (Je tourne sous PostgreSQL 9.6 sous W10). Faut-il chercher à un endroit spécifique ?

Sous PgAdmin, j'ai passé des champs actif_objet de TRUE à FALSE et Postgresql m'indique le message suivant :


ERREUR:  la valeur d'une clé dupliquée rompt la contrainte unique « prk_constraint_commandes_bons »
DETAIL:  La clé « (id_bon, id_commande)=(2, 8) » existe déjà.
CONTEXT:  instruction SQL « INSERT INTO COMMANDES_BONS VALUES (i,j) »
fonction PL/pgsql commandes_insertion_commandes_bons(), ligne 14 à instruction SQL
instruction SQL « INSERT INTO COMMANDES (ID_CARTON) (SELECT ID_CARTON FROM CARTONS WHERE QTE_OBJET_RESTANT_CARTON = NEW.QTE_OBJET_RESTANT_CARTON) »
fonction PL/pgsql cartons_sortie(), ligne 3 à instruction SQL
instruction SQL « update cartons car
set QTE_OBJET_RESTANT_CARTON = (select count(actif_objet) from objets objt
                                   where actif_objet = TRUE
                                   and car.id_carton = objt.id_carton) »
fonction PL/pgsql compte_consommable_actif(), ligne 3 à instruction SQL


En revanche, lorsque je désactive le trigger de la table OBJETS et que je modifie manuellement les données du champ QTE_OBJET_RESTANT_CARTON de la table CARTONS tout se passe bien !!!! Les tables différentes tables reçoivent alors correctement les insertions de données.


Arf, arf, arf...

Hors ligne

#4 24/12/2016 17:42:15

PunkAndBad
Membre

Re : Problème de cohabitation de triggers

Bonjour,

En arrivant à observer les traces du trigger 1, je m'aperçois que celui-ci ne fonctionne pas comme je le souhaite.
Son fonctionnement est "normal" lorsque je tape directement dans le champ QTE_OBJET_RESTANT_CARTON  de la table CARTONS, par contre lorsque le trigger 2 s'active le trigger 1 ne récupère pas correctement les ID_CARTONS.
Je sèche un peu sur le trigger 1 pour trouver la requête qui va identifier les bons ID_CARTON mais je ne désespère pas en cette période de Noël ;-)

Bonnes fêtes à vous tous.

Hors ligne

#5 30/12/2016 16:09:54

PunkAndBad
Membre

Re : Problème de cohabitation de triggers

Bonjour,

J'ai enfin trouvé la solution pour récupérer correctement l'ID_CARTON de la table CARTONS lorsque les triggers se mettent en action :
Voici le code :

CREATE OR REPLACE FUNCTION cartons_sortie() RETURNS TRIGGER AS $$
DECLARE
init INTEGER;
fin INTEGER;
res INTEGER;
BEGIN
    init := OLD.quantite_consommable_restant_carton;
    fin := NEW.quantite_consommable_restant_carton;
    res := init - fin;
    PERFORM ID_CARTON FROM CARTONS WHERE quantite_consommable_restant_carton = (res);
         RAISE WARNING'La valeur RES vaut : %', res;
        IF RES != 0 THEN
        RAISE WARNING'La valeur ID_CARTON vaut : %', NEW.ID_CARTON;
        INSERT INTO COMMANDES (ID_CARTON) VALUES(NEW.ID_CARTON);
        END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

create trigger sortie_cartons
after update on cartons
for each row
    execute procedure cartons_sortie();

Passez de bonnes fêtes.

Hors ligne

Pied de page des forums