<?xml version="1.0" encoding="iso-8859-1"?>
<document>
   <titre>Introduction à PostgreSQL</titre>
   <contenu>
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fr-ch" lang="fr-ch">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>

<h2>Introduction à PostgreSQL</h2>

<p class="abstract">
Ce document parcours les différentes fonctionnalités du puissant 
gestionnaire de base de données PostgreSQL. Le but étant de vous donner un aperçu rapide
des avantages que son utilisation pourrait vous apporter.
Pour comprendre les exemples qui suivent il faut être familier avec le langage SQL.
</p>

<p>PostgreSQL est un système de gestion de base de données relationnelle et objet (SGBDOR). Ces
fonctionnalités sont comparables à celles des ces concurrents propriétaires comme Oracle.</p>

<p>PostgreSQL offre : </p>

<ul>
<li>La possibilité d’imposer des contraintes à l’insertion des données</li>
<li>Les contraintes d’intégrités (garantie d’intégrité des données)</li>
<li>La possibilité de créer des vues</li>
<li>La possibilité d’hériter des tables et des types de données</li>
<li>Les procédures stockées (programmation coté serveur)</li>
<li>Les transactions (plusieurs étapes en une seule opération)
<li>Les triggers (gestion des événements)</li>
</ul>

<p>Pour aborder ces notions rien ne vaut le fameux exemple des clients,
des produits et des commandes. Ce schéma sera utilisé dans ce document afin de mettre
en pratique les possibilités de PostgreSQL.</p>

<ul>
<li><a href="./postgresql.sql.html">Fichier SQL avec tout les exemples format HTML</a>.</li>
<li><a href="./postgresql.sql">Fichier SQL avec tout les exemples format texte</a> ;</li>
</ul>

<h2>Structure de la base données</h2>

<p>La structure de la base de donnée sera la suivante :</li>

<ul>
<li><strong>Clients</strong></li>
<li><strong>Commandes</strong> &raquo; Clients</li>
<li><strong>Produits</strong></li>
<li>Produit &laquo; <strong>table de liaison</strong> &raquo; Commande
</ul>

<p>Une fois traduit en SQL on pourrait obtenir cela : </p>

<pre>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TABLE</span>  clients
 (
     pkey SERIAL <span style="font-weight: bold;">PRIMARY</span> <span style="font-weight: bold;">KEY</span> ,
     nom <span style="color: #800000;">VARCHAR</span> (<span style="color: #0000ff;">50</span> ) <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span> ,
     prenom <span style="color: #800000;">VARCHAR</span> (<span style="color: #0000ff;">50</span> ) <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span>
 );
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TABLE</span>  commandes
 (
     pkey SERIAL <span style="font-weight: bold;">PRIMARY</span> <span style="font-weight: bold;">KEY</span> ,
     <span style="font-style: italic;color: #808080;">-- la commande pointe sur un client</span>
     client_pkey <span style="color: #800000;">INTEGER</span> <span style="font-weight: bold;">references</span>  clients <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span> ,
     total <span style="color: #800000;">NUMERIC</span> (<span style="color: #0000ff;">10</span> ,<span style="color: #0000ff;">2</span> )
 );
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TABLE</span>  produits
 (
     pkey SERIAL <span style="font-weight: bold;">PRIMARY</span> <span style="font-weight: bold;">KEY</span> ,
     <span style="font-style: italic;color: #808080;">-- la contrainte "prix_positif" impose  un prix strictement positif</span>
     prix <span style="color: #800000;">NUMERIC</span> (<span style="color: #0000ff;">10</span> ,<span style="color: #0000ff;">2</span> ) <span style="font-weight: bold;">CONSTRAINT</span>  prix_positif <span style="font-weight: bold;">CHECK</span>  (prix &gt; <span style="color: #0000ff;">0</span> ) <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span> ,
     <span style="font-style: italic;color: #808080;">-- l’intitulé du produit doit être unique</span>
     <span style="font-weight: bold;">label</span> <span style="color: #800000;">VARCHAR</span> (<span style="color: #0000ff;">50</span> ) <span style="font-weight: bold;">UNIQUE</span> <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span>
 );
<span style="font-style: italic;color: #808080;">-- cette table indique la quantité d’un produit pour une commande</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TABLE</span>  produit_commande
 (
     <span style="font-style: italic;color: #808080;">-- "ON DELETE CASCADE" indique que si la ligne de données</span>
     <span style="font-style: italic;color: #808080;">-- référencée est supprimée celle-ci doit l'être également</span>
     commande_pkey <span style="color: #800000;">INTEGER</span> <span style="font-weight: bold;">references</span>  commandes <span style="font-weight: bold;">ON</span> <span style="font-weight: bold;">DELETE</span> <span style="font-weight: bold;">CASCADE</span> ,
     produit_pkey <span style="color: #800000;">INTEGER</span> <span style="font-weight: bold;">references</span>  produits <span style="font-weight: bold;">ON</span> <span style="font-weight: bold;">DELETE</span> <span style="font-weight: bold;">CASCADE</span> ,
     <span style="font-style: italic;color: #808080;">-- la quantité doit être strictement positive</span>
     quantite <span style="color: #800000;">INTEGER</span> <span style="font-weight: bold;">CONSTRAINT</span>  quantite_positive <span style="font-weight: bold;">CHECK</span>  (quantite &gt; <span style="color: #0000ff;">0</span> ) <span style="font-weight: bold;">NOT</span> <span style="font-weight: bold;">NULL</span> ,
     <span style="font-style: italic;color: #808080;">-- la clé primaire est formée de la clé du produit et de la commande</span>
     <span style="font-weight: bold;">PRIMARY</span> <span style="font-weight: bold;">KEY</span> (produit_pkey, commande_pkey)
 );
</pre>

<p>PostgreSQL gère automatiquement les contraintes d’intégrités lié aux cléfs étrangères. Par exemple il est encore impossible d’insérer une commande. Il faut avant cela insérer un client puis ensuite seulement on pourra insérer une commande qui référence ce client.
</p>

<pre>
-- l’insértion de la commande provoque une erreur
<span style="font-weight: bold;">INSERT</span> <span style="font-weight: bold;">INTO</span>  commandes (client_pkey,total) <span style="font-weight: bold;">VALUES</span>  (<span style="color: #0000ff;">1</span> ,<span style="color: #0000ff;">0</span> );
<span style="font-weight: bold;">INSERT</span> <span style="font-weight: bold;">INTO</span>  clients (nom,prenom) <span style="font-weight: bold;">VALUES</span>  (<span style="color: #dd0000;">'Dupont'</span> , <span style="color: #dd0000;">'André'</span> );

-- mais l’inverse est correct
<span style="font-weight: bold;">INSERT</span> <span style="font-weight: bold;">INTO</span>  clients (nom,prenom) <span style="font-weight: bold;">VALUES</span>  (<span style="color: #dd0000;">'Dupont'</span> , <span style="color: #dd0000;">'André'</span> );
<span style="font-weight: bold;">INSERT</span> <span style="font-weight: bold;">INTO</span>  commandes (client_pkey,total) <span style="font-weight: bold;">VALUES</span>  (<span style="color: #0000ff;">1</span> ,<span style="color: #0000ff;">0</span> );
</pre>

<p><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/tutorial-sql.html">Documentation en français sur la création de base de données avec PostgreSQL et sur le langage SQL</a>.</p>

<h2>Les vues</h2>

<p>Les vues permettent de créer une abstraction sur des requètes fréquentes. Ces requètes ne prennent
pas de paramètres. On leur donne un nom. On peut ensuite les utiliser dans toute l’applications.</p>

<p>Cette vue permet de sélectionner les informations du produit ainsi que la quantité vendu à ce jour :</p>

<pre>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">VIEW</span>  vente_produits <span style="font-weight: bold;">AS</span> 
<span style="font-weight: bold;">SELECT</span>  produits.*, 
(<span style="font-weight: bold;">SELECT</span> <span style="color: #000080;">SUM</span> (produit_commande.quantite) 
        <span style="font-weight: bold;">FROM</span>  produit_commande <span style="font-weight: bold;">WHERE</span>  produit_commande.produit_pkey=produits.pkey) <span style="font-weight: bold;">
AS</span>  quantite <span style="font-weight: bold;">FROM</span>  produits;
</pre>

<p><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/tutorial-views.html">Documentation sur les vues en français</a>.</p>

<h2>Les procédures stockées</h2>

<p>PostgreSQL permet de créer des programmes dans un langage de procédure. Ces programmes sont
stockés et executés sur le serveur. Les avantages sont multiples : </p>

<ul>
<li>Cela permet dans certains cas d’améliorer l’efficacité des traitements en évitant des aller et retour entre le PostgreSQL et le client de la base.</li>
<li>Cela offre une grande souplesse d’utilisation et une plus grande
abstraction par rapport à la base de données.</li>
</ul>

<p>Comme exemple de procédure, réalisons une fonction qui retourne tout les produits d’une commandes
et les quantités associées : </p>

<pre>
<span style="font-style: italic;color: #808080;">-- créer un type de donné correspondant à ligne de réponse
-- est nécessaire pour ce qui va suivre</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TYPE</span>  produit_de_la_commande 
<span style="font-weight: bold;">AS</span>  (pkey <span style="color: #800000;">INTEGER</span> , prix <span style="color: #800000;">NUMERIC</span> (<span style="color: #0000ff;">10</span> ,<span style="color: #0000ff;">2</span> ), <span style="font-weight: bold;">label</span> <span style="color: #800000;">VARCHAR</span> (<span style="color: #0000ff;">50</span> ), quantite <span style="color: #800000;">INTEGER</span> );

<span style="font-style: italic;color: #808080;">-- la fonction "produits_de_la_commande" retourne tout les 
-- produits d’une commande choisie avec les quantités</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">OR</span> <span style="font-weight: bold;">REPLACE</span> <span style="font-weight: bold;">FUNCTION</span>  produits_de_la_commande(<span style="color: #800000;">INTEGER</span> ) 
RETURNS SETOF produit_de_la_commande <span style="font-weight: bold;">AS</span>
 $BODY$
<span style="font-weight: bold;">DECLARE</span>
<span style="font-style: italic;color: #808080;">-- on déclare une variable de travail type "produit_de_la_commande"</span>
 produit produit_de_la_commande;
<span style="font-weight: bold;">BEGIN</span>
<span style="font-style: italic;color: #808080;">-- la clé de la commande est passé comme paramètre. Si ce paramètre n’est</span>
<span style="font-style: italic;color: #808080;">-- nommmé il prend comme valeur $n. N étant la position du paramètre dans le prototype.</span>
<span style="font-weight: bold;">FOR</span>  produit <span style="font-weight: bold;">IN</span> <span style="font-weight: bold;">SELECT</span>  produits.*, produit_commande.quantite <span style="font-weight: bold;">FROM</span>  produits, produit_commande 
<span style="font-weight: bold;">WHERE</span>  commande_pkey=$1 <span style="font-weight: bold;">and</span>  produit_pkey=produits.pkey
     LOOP
         <span style="font-style: italic;color: #808080;">-- cette syntaxe est nécessaire pour retourner plusieurs lignes</span>
         <span style="font-weight: bold;">RETURN</span> <span style="font-weight: bold;">NEXT</span>  produit;
     <span style="font-weight: bold;">END</span>  LOOP;
<span style="font-weight: bold;">RETURN</span> ;
<span style="font-weight: bold;">END</span> ;
 $BODY$
 LANGUAGE <span style="color: #dd0000;">'plpgsql'</span> ;
</pre>

<p>L’intérêt d’une telle fonction est assez faible, mais elle permet d’obtenir une abstraction
intéressante que nous allons utiliser par la suite : </p>

<pre>
<span style="font-style: italic;color: #808080;">-- cette fonction calcul le total d’une commande, le mets à jour et le renvoi</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">OR</span> <span style="font-weight: bold;">REPLACE</span> <span style="font-weight: bold;">FUNCTION</span>  calcul_total(<span style="color: #800000;">INTEGER</span> , <span style="font-weight: bold;">OUT</span>  commande_total <span style="color: #800000;">NUMERIC</span> ) <span style="font-weight: bold;">AS</span>
 $BODY$
<span style="font-weight: bold;">DECLARE</span>
 produit produit_de_la_commande;
<span style="font-weight: bold;">BEGIN</span>
 commande_total=<span style="color: #800080;">0.0</span> ;
<span style="font-weight: bold;">FOR</span>  produit <span style="font-weight: bold;">IN</span> <span style="font-weight: bold;">SELECT</span>  * <span style="font-weight: bold;">FROM</span>  produits_de_la_commande($1)
     LOOP
         commande_total=commande_total+(produit.prix*produit.quantite);
     <span style="font-weight: bold;">END</span>  LOOP;
     <span style="font-style: italic;color: #808080;">-- mise à jour</span>
     <span style="font-weight: bold;">UPDATE</span>  commandes <span style="font-weight: bold;">SET</span>  total=commande_total <span style="font-weight: bold;">WHERE</span>  pkey=$1;
<span style="font-weight: bold;">END</span> ;
 $BODY$
 LANGUAGE <span style="color: #dd0000;">'plpgsql'</span> ;
</pre>

<p>Les choses commence à être intéressantes. Nous avons calculé le total de la commande à l’aide de
<code>produits_de_la_commande</code> puis nous avons mis à jour la ligne de la table commande correspondante,
enfin nous renvoyons le total de la commande via le protoype de la fonction avec le mots clé <code>OUT</code>.
</p>

<p>Nous pouvons utiliser cette fonction de la manière suivante : </p>

<pre>
<span>SELECT</span> * <span>FROM</span> calcul_total(1);
</pre>

<p><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/xplang.html">Documentation en français sur les procédures</a>.</p>

<h2>Les Triggers</h2>

<p>Les triggers (événements) permettent d'éxécuter des procédures quand certaines actions se déclenchent. 
Par exemple, lors de la modification d’un champ ou de sa suppression. On peut choisir déclencher le trigger avant
ou après (<code>BEFORE</code>, <code>AFTER</code>) l'événement.</p>

<p>Cela peut-être très util. Dans ce cas, nous pourrions utiliser cette fonctionnalité pour mettre à jour
le total d’une commande lors de la modification d’une ligne dans la table "produit_commande" : </p>

<pre>
<span style="font-style: italic;color: #808080;">-- un trigger a besoin d’une fonction spécial qui retourne un trigger</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">OR</span> <span style="font-weight: bold;">REPLACE</span> <span style="font-weight: bold;">FUNCTION</span>  calcul_total_trigger() RETURNS <span style="font-weight: bold;">TRIGGER</span> <span style="font-weight: bold;">AS</span>
 $BODY$
<span style="font-weight: bold;">BEGIN</span>
     <span style="font-style: italic;color: #808080;">-- NEW correspond à la ligne qui vient d'être créé/modifiée</span>
     <span style="font-style: italic;color: #808080;">-- PERFORM est nécessaire car la valeur de retour ne nous interesse pas</span>
     PERFORM calcul_total(NEW.commande_pkey);
     <span style="font-weight: bold;">RETURN</span> <span style="font-weight: bold;">NEW</span> ;
<span style="font-weight: bold;">END</span> ;
 $BODY$
 LANGUAGE <span style="color: #dd0000;">'plpgsql'</span> ;

<span style="font-style: italic;color: #808080;">-- le trigger qui réagis sur INSERT ou UPDATE</span>
<span style="font-weight: bold;">CREATE</span> <span style="font-weight: bold;">TRIGGER</span>  recalcul_total
     <span style="font-weight: bold;">AFTER</span> <span style="font-weight: bold;">INSERT</span> <span style="font-weight: bold;">OR</span> <span style="font-weight: bold;">UPDATE</span> <span style="font-weight: bold;">ON</span>  produit_commande <span style="font-weight: bold;">FOR</span> <span style="font-weight: bold;">EACH</span> <span style="font-weight: bold;">ROW</span>
     <span style="font-weight: bold;">EXECUTE</span> <span style="font-weight: bold;">PROCEDURE</span>  calcul_total_trigger();
</pre>

<p><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/triggers.html">Documentation en français sur les Triggers</a>.</p>

<h2>Autres points importants non abordés</h2>

<ul>
<li><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/tutorial-inheritance.html">Héritage de table</a></li>
<li><a href="http://traduc.postgresqlfr.org/pgsql-8.1.2-fr/tutorial-transactions.html">Les transactions</a>
</ul>

   </contenu>
      
<zone>

       <h3>Liens</h3>
       <ul>
          <li><a href="./postgresql.sql.html">Fichier SQL avec tout les exemples format HTML</a> ;</li>
          <li><a href="./postgresql.sql">Fichier SQL avec tout les exemples format texte</a> ;</li>
          <li><a href="http://traduc.postgresqlfr.org/">Documentation PostgreSQL traduite</a> ;</li>
          <li><a href="http://postgresqlfr.org/">Le site de PostgreSQL en français</a> ;</li>
          <li><a href="http://www.postgresql.org/">Le site de PostgreSQL</a>.</li>
       </ul>
       <dl>
       <dt>Auteur</dt>
       <dd>Batiste Bieler</dd>
       <dt>Licence</dt>
       <dd><a href="http://fr.wikipedia.org/wiki/LGPL">LGPL</a></dd>
       </dl>
      
   </zone>
</document>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    		