-- Fichier d exemple pour PostgresSQL -- -- @author : Batiste Bieler -- @company : http://dosimple.ch -- @version : 0.1 -- -- Copyright (C) 2006 Bieler Batiste -- -- This library is free software; you can redistribute it and/or -- modify it under the terms of the GNU Lesser General Public -- License as published by the Free Software Foundation; either -- version 2.1 of the License, or (at your option) any later version. -- -- This library is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -- Lesser General Public License for more details. -- -- You should have received a copy of the GNU Lesser General Public -- License along with this library; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- routine de suppression DROP TRIGGER recalcul_total ON produit_commande; DROP FUNCTION calcul_total_trigger(); DROP FUNCTION calcul_total(integer); DROP FUNCTION produits_de_la_commande(integer); DROP TYPE produit_de_la_commande; DROP VIEW vente_produits; DROP TABLE produit_commande; DROP TABLE commandes; DROP TABLE produits; DROP TABLE clients; -- création des tables CREATE TABLE clients ( pkey SERIAL PRIMARY KEY, nom VARCHAR(50) NOT NULL, prenom VARCHAR(50) NOT NULL ); CREATE TABLE commandes ( pkey SERIAL PRIMARY KEY, -- la commande pointe sur un client client_pkey INTEGER references clients NOT NULL, total NUMERIC(10,2) ); CREATE TABLE produits ( pkey SERIAL PRIMARY KEY, -- la contrainte "prix_positif" impose un prix strictement positif prix NUMERIC(10,2) CONSTRAINT prix_positif CHECK (prix > 0) NOT NULL, -- l intitulé du produit doit être unique label VARCHAR(50) UNIQUE NOT NULL ); -- cette table indique la quantité d un produit pour une commande CREATE TABLE produit_commande ( -- "ON DELETE CASCADE" indique que si la ligne de données -- référencée est supprimée celle-ci doit l être également commande_pkey INTEGER references commandes ON DELETE CASCADE, produit_pkey INTEGER references produits ON DELETE CASCADE, -- la quantité doit être strictement positive quantite INTEGER CONSTRAINT quantite_positive CHECK (quantite > 0) NOT NULL, -- la clé primaire est formée de la clé du produit et de la commande PRIMARY KEY(produit_pkey, commande_pkey) ); -- Vue CREATE VIEW vente_produits AS SELECT produits.*, (SELECT SUM(produit_commande.quantite) FROM produit_commande WHERE produit_commande.produit_pkey=produits.pkey) as quantite FROM produits; -- Procédures -- créer un type de donné est nécessaire pour ce qui va suivre CREATE TYPE produit_de_la_commande AS (pkey INTEGER, prix NUMERIC(10,2), label VARCHAR(50), quantite INTEGER); -- la fonction "produits_de_la_commande" retourne tout les produits d une commande choisie avec -- les quantités associées CREATE OR REPLACE FUNCTION produits_de_la_commande(INTEGER) RETURNS SETOF produit_de_la_commande AS $BODY$ DECLARE -- on déclare une variable de travail type "produit_de_la_commande" produit produit_de_la_commande; BEGIN -- la clé de la commande est passé comme paramètre. Si ce paramètre n est -- nommmé il prend comme valeur $n. N étant la position du paramètre dans le prototype. FOR produit IN SELECT produits.*, produit_commande.quantite FROM produits, produit_commande WHERE commande_pkey=$1 and produit_pkey=produits.pkey LOOP -- cette syntaxe est nécessaire pour retourner plusieurs lignes RETURN NEXT produit; END LOOP; RETURN; END; $BODY$ LANGUAGE 'plpgsql'; -- cette fonction calcul le total d'une commande, le mets à jour et le renvoi CREATE OR REPLACE FUNCTION calcul_total(INTEGER, OUT commande_total NUMERIC) AS $BODY$ DECLARE produit produit_de_la_commande; BEGIN commande_total=0.0; FOR produit IN SELECT * FROM produits_de_la_commande($1) LOOP commande_total=commande_total+(produit.prix*produit.quantite); END LOOP; -- mise à jour UPDATE commandes SET total=commande_total WHERE pkey=$1; END; $BODY$ LANGUAGE 'plpgsql'; -- Triggers -- un trigger a besoin d'une fonction spécial qui retourne un trigger CREATE OR REPLACE FUNCTION calcul_total_trigger() RETURNS TRIGGER AS $BODY$ BEGIN -- NEW correspond à notre ligne qui vient d être créé/modifiée -- PERFORM est nécessaire car la valeur de retour ne nous interesse pas PERFORM calcul_total(NEW.commande_pkey); RETURN NEW; END; $BODY$ LANGUAGE 'plpgsql'; -- notre trigger qui réagis sur INSERT ou UPDATE CREATE TRIGGER recalcul_total AFTER INSERT OR UPDATE ON produit_commande FOR EACH ROW EXECUTE PROCEDURE calcul_total_trigger(); -- Quelques données INSERT INTO clients (nom,prenom) VALUES ('Dupont', 'André'); INSERT INTO clients (nom,prenom) VALUES ('Dupond', 'Jaques'); INSERT INTO clients (nom,prenom) VALUES ('Hornoz', 'Sandrine'); INSERT INTO clients (nom,prenom) VALUES ('Potto', 'Hélène'); INSERT INTO produits (prix,label) VALUES (1.2, 'Gomme blanche'); INSERT INTO produits (prix,label) VALUES (9.5, 'Taille crayon en fer blanc'); INSERT INTO produits (prix,label) VALUES (2.3, 'Taille crayon plastique'); INSERT INTO produits (prix,label) VALUES (0.2, 'Crayon'); INSERT INTO commandes (client_pkey,total) VALUES (1,0); INSERT INTO commandes (client_pkey,total) VALUES (2,0); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (1,1,5); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (1,2,1); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (1,3,1); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (1,4,20); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (2,4,10); INSERT INTO produit_commande (commande_pkey,produit_pkey,quantite) VALUES (2,1,4);