IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Requêtes PostgreSQL Discussion :

Trigger gérant plusieurs lignes (insertion ou modification) à la fois


Sujet :

Requêtes PostgreSQL

  1. #1
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut Trigger gérant plusieurs lignes (insertion ou modification) à la fois
    Salut
    J'ai prix une petite appli de gestion de factures.
    La facture est créer avec ses détails (lignefacture) et le client est livré (ou nous recevons les produits) et cette facture est ses détails ne sont plus modifiés. A chaque fois que le client se présente pour payer (ou que nous payons chez le fournisseur) une partie de (ou toute) la facture alors la table règlement est mouvementée.
    L'idée est de faire en sorte que le client ne paye pas plus que ce qu’il nous doit (ou que nous ne payons pas plus que ce qu'on doit au fournisseur). On peut l’assimiler aussi à un prêt bancaire. Il ne faut pas que les remboursements dépassent le capital + l’interêt.
    Exemple
    Facture
    idfacture ! datefacture ! typefacture(vente ou achat)
    1! 02/01/2012!vente

    lignefacture (ou détail facture)
    idfacture ! produit ! quantite ! prixunitaire
    1!CPUI4! 4!30
    1!EHP1755!2!45

    reglement
    idfacture ! idreglement ! datereglement ! montantreglement
    1!1! 02/01/2012!90
    1!2!10/01/2012!70

    Nous voyons que la facture N° 1 fait un total de (4*30)+(2*45)=210. Il ne faut pas alors que le total des différents règlements sur cette facture dépasse 210.
    Cela est il faisable avec un trigger de PL/pgsql?
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Bonjour,

    Je mettrai plutôt une contrainte de type CHECK :
    http://www.postgresql.org/docs/9.1/s...nstraints.html

    Cette contrainte peut appeler une fonction pl/sql qui elle vérifira ceci.

    (ceci étant dit un trigger before insert / update pourra aussi le faire)

  3. #3
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    salut
    J'ai déjà fait avec CHECK...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    CREATE OR REPLACE FUNCTION fncheckreglement(idf integer, mt integer)
      RETURNS boolean AS
    $BODY$
    DECLARE
      totalfacture integer;
      totalreglement integer;
    BEGIN
    SELECT INTO totalfacture sum(lignefacture.quantite*lignefacture.prixunitaire) FROM lignefacture WHERE idfacture=idf;
    SELECT INTO totalreglement coalesce(sum(montantreglement),0)+mt FROM reglement WHERE idfacture=idf;
    IF totalreglement>totalfacture THEN
      RETURN false;
    END IF;
    RETURN true;
    END;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    Mais là je cherche à comprendre le mécanisme de trigger de PostrgreSQL. En faite c'est plutôt une recherche personnelle sur le SGBD.
    Merci d'avance
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  4. #4
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Bein avec un trigger, c'est presque pareil sauf qu'il faudra en faire un pour l'insert un autre pour l'update.

    Et ils devront être before insert / update.

    Il faudra par contre gérer manuellement l'exception en appelant un raise exception.

    Un exemple à adapter :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    CREATE OR REPLACE FUNCTION "_INSERT_SOC_EXCLUSION"()
      RETURNS trigger AS
    $BODY$declare cnt integer;
    begin
    	select count(*) into cnt from t_societe_soc where cli_id = new.cli_id;
    	if cnt > 0 then
    		raise exception unique_violation USING MESSAGE = 'Duplicate CLI_ID in T_PERSONNE_PER table: ' || new.cli_id;
    	end if;
    	return null;
    end;$BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    Le binding du trigger sur la table en question :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    CREATE TRIGGER "_INSERT"
      BEFORE INSERT
      ON t_societe_soc
      FOR EACH ROW
      EXECUTE PROCEDURE "_INSERT_SOC_EXCLUSION"();

  5. #5
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Salut
    La solution donnée n'est pas adaptable car elle ne prend pas en compte les données en insertion ou en update. De plus avec BEFORE les données OLD et NEW sont vides. Par ailleurs les tables de PostegreSQL n'acceptent pas INSTEAD OF. J'avais poser ma question sur un autre forum sans succès. Je pense que la solution avec les triggers n'est pas encore possible.
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  6. #6
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Bonjour,

    Citation Envoyé par alassanediakite Voir le message
    Salut
    La solution donnée n'est pas adaptable car elle ne prend pas en compte les données en insertion ou en update.
    C'est pour ca que je spécifiais qu'il fallait 2 trigger, 1 en insert et 1 en update.


    De plus avec BEFORE les données OLD et NEW sont vides.
    Non pas vraiment, les valeurs new / old sont bien allimentées.

    Par ailleurs les tables de PostegreSQL n'acceptent pas INSTEAD OF. J'avais poser ma question sur un autre forum sans succès. Je pense que la solution avec les triggers n'est pas encore possible.
    Effectivement, mais ici ce n'est pas instead of qui est utilisé.


    Avez-vous au moins testé ?

  7. #7
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    J'ai vraiment essayé. Un lien en mp.
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  8. #8
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut ortho
    Oui étrange pourtant Gleu est une personne qui s'y connais plus que moi ...

    Ceci étant dit en 9.1 :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    create table facture (id integer primary key, type_fac varchar(10));
    create table lig_facture(id integer references facture(id), id_produit integer, quantite integer, val_unit integer, primary key (id, id_produit));
    create table reglement (id_facture integer references facture(id), id_reglement integer, dt_reglement date, mont_reglement integer, primary key(id_facture, id_reglement));
     
     
    insert into facture values (1, 'vente');
    insert into lig_facture values (1, 1, 4, 30), (1, 2, 2, 45);

    Maintenant la fonction trigger + binding :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
    cREATE OR REPLACE FUNCTION _INSERT_REGLEMENT_EXCLUSION()
      RETURNS trigger AS
    $BODY$
    declare 
    	montant integer := 0;
    	montant_init integer := 0;
    begin
    	select COALESCE(sum(mont_reglement), 0) into montant from reglement a where a.id_facture = new.id_facture;
    	select sum(val_unit*quantite) into montant_init from lig_facture where id = new.id_facture;
    	if montant + new.mont_reglement > montant_init then
    		raise exception unique_violation USING MESSAGE = 'Montant trop grand ';
    	end if;
    	return null;
    end;$BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
     
     
    CREATE TRIGGER "_INSERT_TRIG"
      BEFORE INSERT
      ON reglement
      FOR EACH ROW
      EXECUTE PROCEDURE _insert_reglement_exclusion();
    Le test avec une valeur trop grande :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    insert into reglement values (1, 2, now(), 50000000);
     
    ERREUR:  Montant trop grand 
     
     
    ********** Erreur **********
     
    ERREUR: Montant trop grand 
    État SQL :23505
    Le test avec un montant ok :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    insert into reglement values (1, 3, now(), 50);
     
    La requête a été exécutée avec succés : 0 ligne modifiée. La requête a été exécutée en 31 ms.
    edit : ah je viens de voir que l'insert ne c'est pas fait ... je cherche !

  9. #9
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Ok, dans le trigger il faut mettre return new et non return null.

    Sinon en rajoutant, dans le trigger ce genre de code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    raise notice using message = new.montant;
    Vous verrez que les la valeur new / old sont bien alimentées.

  10. #10
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Merci de cette réponse. Je vais voir tout ça.
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

  11. #11
    Membre expert
    Avatar de alassanediakite
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2006
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Mali

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2006
    Messages : 1 599
    Points : 3 590
    Points
    3 590
    Billets dans le blog
    8
    Par défaut
    Salut et très grand merci pour la solution.
    Sur insert:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    -- Function: _insert_reglement_exclusion()
     
    -- DROP FUNCTION _insert_reglement_exclusion();
     
    CREATE OR REPLACE FUNCTION _insert_reglement_exclusion()
      RETURNS trigger AS
    $BODY$
    declare 
    	montant integer := 0;
    	montant_init integer := 0;
    begin
    	SELECT COALESCE(sum(montantreglement), 0) INTO montant FROM reglement a WHERE a.idfacture = new.idfacture;
    	SELECT sum(prixunitaire*quantite) INTO montant_init FROM lignefacture WHERE idfacture = new.idfacture;
    	IF montant + new.montantreglement > montant_init then
    		RAISE 'le montant des règlements dépasse le total de la facture!';
    	end IF;
    	RETURN NEW;
    end;$BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    ALTER FUNCTION _insert_reglement_exclusion()
      OWNER TO postgres;
    sur update:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    CREATE OR REPLACE FUNCTION _update_reglement_exclusion()
      RETURNS trigger AS
    $BODY$
    declare 
    	montant integer := 0;
    	montant_init integer := 0;
    begin
    	SELECT COALESCE(sum(montantreglement), 0) INTO montant FROM reglement a WHERE a.idfacture = new.idfacture AND a.idfacture = OLD.idfacture;
    	SELECT sum(prixunitaire*quantite) INTO montant_init FROM lignefacture WHERE idfacture = new.idfacture AND idfacture = OLD.idfacture;
    	IF montant -old.montantreglement+ new.montantreglement > montant_init then
    		RAISE 'le montant des règlements dépasse le total de la facture!';
    	end IF;
    	RETURN NEW;
    end;$BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    ALTER FUNCTION _update_reglement_exclusion()
      OWNER TO postgres;
    Les deux marchent très bien, même en cas d'insertion ou modification multiples le tout est annuler d'un coup.
    Le monde est trop bien programmé pour être l’œuvre du hasard…
    Mon produit pour la gestion d'école: www.logicoles.com

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 10
    Dernier message: 22/07/2011, 16h20
  2. trigger delete pour plusieurs lignes
    Par Shabata dans le forum Langage SQL
    Réponses: 6
    Dernier message: 30/09/2009, 01h00
  3. Trigger sur plusieurs lignes
    Par Jérôme Lambert dans le forum Développement
    Réponses: 2
    Dernier message: 30/11/2006, 23h28
  4. insertion automatique de plusieurs lignes dans mysql
    Par dejiein dans le forum Requêtes
    Réponses: 2
    Dernier message: 02/06/2006, 10h41
  5. Réponses: 2
    Dernier message: 10/05/2005, 18h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo