le poly SQL

Transcription

le poly SQL
Présentation de SQL
A. Terlutte
December 11, 2006
Ce document est un mémento simplifié des principales commandes du Structured Query Language. Il ne se veut
pas complet ; cela serait inutilement complexe (la documentation PostgreSQL contient 1500 pages). N’hésitez pas à
vous reporter à l’aide en ligne, aux différents manuels ou à internet...
Toutes les commandes données dans ce mémento sont des formes simplifiées des commandes SQL.
Pour avoir la syntaxe complète, reportez-vous aux manuels de références.
Différents manuels de référence de PostgreSQL sont téléchargeables à partir de l’adresse suivante :
http://www.postgresql.org/docs/manuals/
Les commandes PSQL sont données en annexe.
Préambule
Prenez l’habitude de nommer correctement vos identifiants même si les noms sont longs. Cela permet de savoir à quoi
correspond un identifiant... même si c’est plus long à écrire !
villes_codepostal_index
chercheurs_nochercheur_pk
reservations_refexpose_fk
Par contre, à l’intérieur de certaines commandes, vous pourrez utiliser des alias.
1
INTERROGATION
Toute la puissance d’interrogation du langage SQL est contenue dans une seule commande : la commande select
SELECT [ ALL | DISTINCT ] * | expression [ AS AliasColonne ][, ...]
[ FROM ClauseFrom [, ...]]
[ WHERE condition ] ,
[ GROUP BY expression [, ...]]
[ HAVING condition [, ...]]
[ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]
[ ORDER BY expression [ ASC | DESC ][, ...]]
où ClauseFrom peut être :
NomTable [ [ AS ] AliasTable [ ( AliasColonne [, ...] ) ] ]
( select ) [ AS ] AliasTable [ ( AliasColonne [, ...] ) ]
ClauseFrom [ NATURAL ] TypeJointure ClauseFrom [ ON ConditionJointure ]
L’alias de colonne peut servir dans les sections GROUP BY ou ORDER BY mais pas dans les autres expressions de
calcul ou de conditions.
La section 2 développe quelques possibilités offertes pour écrire des expressions SQL. Les conditions sont des
expressions à résultat booléen ; reportez-vous aussi à la section 2 pour les conditions.
1
Les expressions dans les colonnes peuvent utiliser les fonctions AVG(expression ), MIN(expression ), MAX(expression ),
SUM(expression ), COUNT(expression ). On peut préciser ALL ou DISTINCT dans la fonction (qui ne tient compte
que des valeurs non nulles). La fonction Count peut ne pas s’appliquer à un champ : COUNT(*).
Si on ouvre deux tables simultanément, le résultat de la sélection est le produit (cartésien) des deux tables.
Exécutez, pour vérifier cette assertion, la commande
select count(*) from salles;
select count(*) from exposes;
select count(*) from exposes,salles;
La jointure s’obtient par la sélection d’un attribut qui est commun aux deux tables.
select codeexpose,codesalle
from exposes,salles
where codesalle=refsalle;
Pour éviter toute ambiguïté, lorsque plusieurs tables sont ouvertes, il faut préciser le nom de la table avant le nom
du champ
select exposes.codeexpose,salles.codesalle
from exposes,salles
where salles.codesalle=exposes.refsalle;
On peut utiliser des alias pour les noms de tables
select ex.codeexpose,sl.codesalle
from exposes as ex,salles as sl
where sl.codesalle=ex.refsalle;
On peut aussi relier deux tables par l’opérateur JOIN
select ex.codeexpose,sl.codesalle
from exposes as ex join salles as sl on sl.codesalle=ex.refsalle;
Si les champs de la jointure portent le même nom dans les deux tables, on peut simplifier l’écriture avec NATURAL
JOIN ; la jointure s’effectue alors sur tous les champs de même nom.
Sur plus de deux tables, la technique est similaire
select co.nomeco, au.nomeco
from ((economistes as co left join exposes as ex on co.codeeco=ex.refconf)
join reservations as re on ex.codeexpose=re.refexpose)
join economistes as au on re.refeco=au.codeeco;
L’opérateur LEFT JOIN permet de relier deux tables en faisant apparaître tous les éléments d’une table même si la
condition de jointure n’est pas satisfaite.
select co.nomeco, ex.titre
from economistes as co left join exposes as ex on co.codeeco=ex.refconf);
fera apparaître tous les économistes même s’ils ne font pas d’exposés.
Il existe évidemment un opérateur RIGHT JOIN.
Vous remarquerez aussi que la syntaxe de ClauseFrom autorise l’utilisation d’une autre clause select. On peut
ainsi utiliser le résultat d’une requête comme étant une nouvelle table ; il faut obligatoirement utiliser un alias pour
cette sous-requête.
December 11, 2006 à 22h02
2/39
December 11, 2006 à 22h02
Une sous-requête peut aussi être utilisée dans une condition ; dans ce cas, l’alias n’est pas utilisé. Dans une
condition, la sous-requête peut apparaître là où une liste aurait pu être utilisée. Il s’agit des conditions utilisant les
opérateurs IN, > ALL, >= ALL,... > ANY,... ; la sous-requête doit fournir une liste, donc une seule colonne.
Une sous-requête peut aussi apparaître, lorsqu’elle fournit une valeur unique, avec des opérateurs classiques de
comparaison =, >...
Avec l’opérateur EXISTS, une ligne de la requête principale sera affichée si la sous-requête est non vide. Dans la
sous-requête, il y a souvent une référence à la requête principale.
Dans le cas des opérations algébriques sur les requêtes (union, intersection, différence), il est nécessaire que les
différentes requêtes aient la même structure (même nombre de colonnes et même type de données).
2
FONCTIONS ET EXPRESSIONS
PostgreSQL offre de nombreuses fonctions. La plupart des fonctions que l’on rencontre dans les langages de programmation sont disponibles ; si vous avez besoin d’une opération ou d’un calcul sur certains types de données, consultez
l’adresse suivante pour vérifier s’il n’existe pas déjà :
http://www.postgresql.org/docs/8.1/interactive/functions.html
Voici quelques fonctions ou opérateurs disponibles en SQL.
2.1
expressions arithmétiques
Les opérateurs arithmétiques habituels sont disponibles mais SQL en propose d’autres
%
modulo
11%3 vaut 2
ˆ
exposant
4ˆ3 vaut 4*4*4=64
|/
racine carrée
|/ 9 vaut 3
...
Toutes les fonctions classiques existent et de nombreuses autres...
2.2
expressions caractères
L’opérateur || effectue la concaténation de chaînes de caractères.
Toutes les fonctions classiques existent :
length(chaîne ),
lower(chaîne ),
substring(chaîne [from PositionDépart ] [for NombreCaractères ] ),
position(SousChaîne in chaîne )...
et de nombreuses autres, avec des syntaxes particulières.
2.3
expressions dates
Les opérateurs + et - permettent aussi d’ajouter ou de soustraire des dates, des horaires et des entiers... Reportez-vous
aux documentations pour connaître les différentes possibilités.
Les dates devraient être, par défaut, sous la forme année-mois-jour heure:minute:seconde mais la configuration
peut spécifier d’autres formats.
Dans une expression, une date ou un horaire peuvent souvent être écrites directement entre apostrophes (exemple
’2006-11-27’) mais il faut parfois préciser le type (exemple date ’2006-11-27’)
Les fonctions CURRENT_DATE et CURRENT_TIME fournissent la date et l’heure actuelles.
La fonction EXTRACT permet d’extraire toutes sortes d’informations contenues dans une date ou d’un horaire
(l’année, les minutes,... mais aussi le trimestre, le numéro de semaine...).
Interval présente une quantité dans une certaine unité.
December 11, 2006 à 22h02
3/39
December 11, 2006 à 22h02
Voici quelques exemples d’expressions valides :
date ’2001-09-28’ + interval ’1 hour’
date ’2001-09-28’ + time ’03:00’
timestamp ’2001-09-28 01:00’ + interval ’23 hours’
date ’2001-10-01’ - date ’2001-09-28’
date ’2001-10-01’ - integer ’7’
900 * interval ’1 second’
2.4
vaut
vaut
vaut
vaut
vaut
vaut
’2001-09-28 01:00:00’
’2001-09-28 03:00:00’
’2001-09-29 00:00:00’
integer ’3’
date ’2001-09-24’
interval ’00:15:00’
expressions booléennes
On peut tester si une expression, souvent une colonne, est nulle
expression IS NULL
expression IS NOT NULL
Les conditions peuvent utiliser les opérateurs habituels (=, <> etc...) mais aussi
expression
expression
expression
expression
BETWEEN expression AND expression
IS [ NOT ] NULL
[ NOT ] LIKE ’modèle ’ avec les jokers % pour une chaîne quelconque et _ pour un caractère
[ NOT ] IN (liste | selection )
Une structure CASE permet de faire un calcul alternatif
CASE WHEN condition THEN expression
WHEN condition THEN expression
....
ELSE expression
END
3
CREATION D’UTILISATEURS
3.1
Création de la base à partir du terminal
CREATEUSER options NomUtilisateur
Les options principales sont
- -createdb l’utilisateur aura le droit de créer des bases de données
- -no-createdb l’utilisateur n’aura pas le droit de créer des bases de données
- -createrole l’utilisateur aura le droit de créer des utilisateurs
- -no-createrole l’utilisateur n’aura pas le droit de créer des utilisateurs
- -pwprompt l’utilisateur aura à utiliser un mot de passe
- -host hote vous précisez la machine hote sur laquelle se trouve le serveur.
- -username utilisateur vous précisez le nom de l’utilisateur qui crée ces nouveaux utilisateurs.
Il existe des abréviations -d pour - -createdb ou -h pour - -host ; reportez-vous aux documentations pour les
connaître.
3.2
Création d’un utilisateur ou d’un groupe
CREATE USER NomUtilisateur [ WITH ] options
est maintenant un alias de la commande
CREATE ROLE NomUtilisateur [ WITH ] options
Les options principales sont
createdb l’utilisateur aura le droit de créer des bases de données
December 11, 2006 à 22h02
4/39
December 11, 2006 à 22h02
nocreatedb l’utilisateur n’aura pas le droit de créer des bases de données
createrole l’utilisateur aura le droit de créer d’autres utilisateurs.
nocreaterole l’utilisateur n’aura pas le droit de créer d’utilisateur.
login indique que l’utilisateur aura le droit de se connecter.
nologin indique que l’utilisateur n’aura pas le droit de se connecter ; utile pour créer un compte d’administrateur.
C’est l’option par défaut.
in role NomGroupe crée l’utilisateur et le place dans un groupe.
4
CREATION DE BASE
Une fois la base conçue, c’est à dire une fois le MCD et le MLD conçus, quelques commandes sont nécessaires pour
créer d’abord la base, puis chacune des tables.
4.1
Création de la base à partir du terminal
La commande createdb permet de créer une base sans avoir à lancer le terminal postgreSQL par la commande psql.
CREATEDB - -host hote - -username utilisateur NomBase
La documentation de postgreSQL renvoie vers les explications de la commande CREATE DATABASE mais il est plus
logique de créer une base de données sans être connecté à une autre base.
4.2
Création de la base
Lorsque vous êtes dans un terminal postgreSQL, vous pouvez créer une nouvelle base par la commande CREATE
DATABASE mais cela signifie que vous êtes déjà connecté à une base...
CREATE DATABASE NomBase
[ [ WITH ] [ OWNER [=] Proprétaire ]
[ TEMPLATE [=] BaseModèle ]
[ ENCODING [=] encodage ] ]
Le nom de la base ne doit pas exister.
Par défaut, le créateur est propriétaire.
La commande PSQL \c permet de se connecter à une base, donc de changer de base de travail.
4.3
Renommage de la base
ALTER DATABASE NomBase RENAME TO NouveauNom
4.4
Suppression de la base
DROP DATABASE NomBase
5
5.1
STRUCTURE DE TABLE
Types de données
Les types les plus courants sont :
VARCHAR(longueur ) ou CHARACTER VARYING(longueur )
INTEGER
REAL
NUMERIC(LongueurTotale,NombreDécimales )
DATE
December 11, 2006 à 22h02
5/39
December 11, 2006 à 22h02
BOOLEAN
....
Mais voici la liste quasi-complète des types SQL (tout au moins en PostgreSQL 8.1.4) :
Name
Aliases
Description
bigint
int8
signed eight-byte integer
bigserial
serial8
autoincrementing eight-byte integer
bit [ (n) ]
fixed-length bit string
bit varying [ (n) ]
varbit
variable-length bit string
boolean
bool
logical Boolean (true/false)
box
rectangular box in the plane
bytea
binary data ("byte array")
character varying [ (n) ]
varchar [ (n) ]
variable-length character string
character [ (n) ]
char [ (n) ]
fixed-length character string
cidr
IPv4 or IPv6 network address
circle
circle in the plane
date
calendar date (year, month, day)
double precision
float8
double precision floating-point number
inet
IPv4 or IPv6 host address
integer
int, int4
signed four-byte integer
-2147483648 to +2147483647
interval [ (p) ]
time span
line
infinite line in the plane
lseg
line segment in the plane
macaddr
MAC address
money
currency amount
numeric [ (p, s) ]
decimal [ (p, s) ] exact numeric of selectable precision
path
geometric path in the plane
point
geometric point in the plane
polygon
closed geometric path in the plane
real
float4
single precision floating-point number
smallint
int2
signed two-byte integer
-32768 to +32767
serial
serial4
autoincrementing four-byte integer
text
variable-length character string
time [ (p) ] [ without time zone ]
time of day
time [ (p) ] with time zone
timetz
time of day, including time zone
timestamp [ (p) ] [ without time zone ]
date and time
timestamp [ (p) ] with time zone
timestamptz
date and time, including time zone
La time zone spécifie le décalage horaire.
Le type money est déconseillé ; le type numeric est conseillé pour le remplacer.
Les types serial et bigserial sont des types autoincrémentés, tout à fait adaptés aux identifiants. Définir une
colonne de ce type définit une séquence qui servira pour la génération des valeurs insérées dans cette colonne.
Il faudra utiliser le mot clé DEFAULT lors des insertions dans la table. La séquence sera suivie indépendamment des
suppressions dans la table ou des insertions n’utilisant pas DEFAULT. Ceci peut mener à des doublons et la déclaration
d’une colonne de type serial ne dispense pas de la contrainte UNIQUE.
5.2
Création de table
La création d’une table nécessite la définition du nom de la table et la définition des colonnes qui la composent. Chaque
colonne a un nom et un type de données. De plus, il est possible de définir certaines contraintes d’intégrité de la table :
structure : la valeur de la clé primaire est unique et toujours définie,
domaine : les valeurs prises par un attribut doivent vérifier des contraintes,
December 11, 2006 à 22h02
6/39
December 11, 2006 à 22h02
référence :
les valeurs d’une clé étrangère doivent correspondre à des valeurs existantes dans la table d’origine.
La vérification de certaines contraintes peut être demandée dès la création de la table. Elle sera assurée par le
système.
CREATE TABLE NomTable (
{ NomColonne Type [ DEFAULT expression ] [ ContrainteColonne [ ...
| ContrainteTable }
[, ... ]
)
] ]
où ContrainteColonne peut être :
[ CONSTRAINT NomContrainte ]
{ NOT NULL |
NULL |
UNIQUE |
PRIMARY KEY |
CHECK (expression ) |
REFERENCES TableReliée [ ( ColonneReliée ) ] }
et ContrainteTable peut être :
[ CONSTRAINT NomContrainte ]
{ UNIQUE ( NomColonne [, ... ] ) |
PRIMARY KEY ( NomColonne [, ... ] ) |
CHECK ( expression ) |
FOREIGN KEY ( NomColonne [, ... ] ) REFERENCES TableReliée [ ( ColonneReliée [, ...
] ) ] }
D’après la syntaxe, le nom de contrainte est facultatif. Mais il est préférable de nommer toutes les contraintes ;
dans certains cas, c’est même obligatoire (quand plusieurs contraintes portent sur une même colonne).
5.3
Modifications de table
ALTER TABLE [ ONLY ] NomTable
ADD [ COLUMN ] NomColonne type [ ContrainteColonne [ ...
] ]
ALTER TABLE [ ONLY ] NomTable
DROP [ COLUMN ] NomColonne
ALTER TABLE [ ONLY ] NomTable
ALTER [ COLUMN ] NomColonne { SET DEFAULT expression | DROP DEFAULT }
ALTER TABLE [ ONLY ] NomTable
ALTER [ COLUMN ] NomColonne { SET | DROP } NOT NULL
ALTER TABLE [ ONLY ] NomTable
RENAME [ COLUMN ] NomColonne TO NouveauNomColonne
ALTER TABLE NomTable
RENAME TO NouveauNomTable
ALTER TABLE [ ONLY ] NomTable
December 11, 2006 à 22h02
7/39
December 11, 2006 à 22h02
ADD NouveauNomTable
ALTER TABLE [ ONLY ] NomTable
ADD ContrainteTable
ALTER TABLE [ ONLY ] NomTable
DROP CONSTRAINT ContrainteTable
ALTER TABLE NomTable
OWNER TO NouveauPropriétaire
5.4
Suppression de table
DROP TABLE NomTable [, ...]
5.5
Quelques exemples
alter table chercheurs
add constraint chercheurs_nochercheur_pk primary key (nochercheur);
alter table parcelles
add constraint parcelles_refsite_fk foreign key (refsite) references sites(nosite);
alter table parcelles
add constraint testlg check (longueur>largeur);
6
INDEXATION
Les index accélèrent les recherches mais alourdissent la base. Si vous estimez qu’un champ va être l’objet de recherches
fréquentes, il peut être judicieux de créer un index sur ce champ. Par exemple, PostgreSQL crée une table d’index
lorsque l’utilisateur déclare une clé primaire.
Les index servent évidemment principalement lors de la commande SELECT, pour les jointures... mais servent
aussi pour les commandes UPDATE, DELETE...
On peut aussi créer des index sur des expressions, en créer sur une partie de table...
Il existe différents types d’index (B-Tree, R-Tree, Hash, GiST) correspondant à différentes organisations dans les
tables d’index. Les B-Trees sont utilisés par défaut et correspondent aux utilisations les plus fréquentes, mais il faut
savoir que d’autres types sont possibles : pour une recherche en deux dimensions,...
Les Hash index n’ont d’intérêt que pour une recherche avec un critère d’égalité. Ils offrent des performances de
recherche équivalentes à celles des B-Trees, mais leur taille et leur temps de construction sont meilleurs.
Nous ne donnerons que l’utilisation des B-Trees. La commande la plus simple pour construire une table d’index
est la suivante.
CREATE INDEX NomIndex ON NomTable (NomChamp )
Si les recherches sont fréquentes, on peut aussi indexer sur une expression.
CREATE INDEX NomIndex ON NomTable (expressions );
On peut aussi indexer sur plusieurs champs.
December 11, 2006 à 22h02
8/39
December 11, 2006 à 22h02
CREATE INDEX test2_mm_idx ON test2 (major, minor);
sera utile pour des recherches comme
SELECT colonne FROM test2 WHERE major = constant AND minor = constant;
Il peut être nécessaire de créer des index à entrées uniques. Il serait interdit d’avoir deux lignes de la table ayant
même clé, même valeur d’index.
CREATE UNIQUE INDEX NomIndex ON NomTable (NomColonne [, ...])
ATTENTION : quand l’utilisateur crée des contraintes primary key ou unique sur une table, PostgreSQL génère
automatiquement des index uniques. Les créer par la commande create index dupliquerait les tables d’index.
Enfin on peut créer un index sur une partie de table si on est sûr que les recherches ne porteront que sur cette
partie.
CREATE INDEX NomIndex ON NomTable (NomChamp ) WHERE condition
Cela diminue la taille de la table d’index, accélère la recherche et la mise à jour. Si une recherche s’effectue en
dehors des valeurs de la table d’index, celle-ci n’est tout simplement pas utilisée.
CREATE INDEX factures_montant_idx ON factures (montant) WHERE paye is not true;
L’index serait utilisé par postgreSQL même pour des requêtes n’utilisant pas le montant comme
SELECT nofacture FROM factures WHERE paye is not true AND nofacture like ’2006*’;
L’exemple suivant illustre une méthode garantissant des lignes uniques sur une partie de la table, multiples sur le
reste.
CREATE TABLE tests (
subject text,
target text,
success boolean,
...
);
L’index va permettre de garantir que pour les lignes ’successfull’, la correspondance sujet/cible est unique.
CREATE UNIQUE INDEX tests_success_constraint ON tests (subject, target) WHERE success;
Dans les applications réelles, l’utilisation de tables d’index est une question majeure. Mais déterminer si un index
va améliorer l’accès à une table est un problème complexe. PostgreSQL préconise l’emploi des commandes ANALYZE
et EXPLAIN sur les données réelles.
Lors de la création d’une table avec les lignes qu’elle contient, il est préférable d’insérer d’abord les lignes puis de
créer les index plutôt que de mettre à jour un index à chaque insertion.
December 11, 2006 à 22h02
9/39
December 11, 2006 à 22h02
7
CONTENU D’UNE TABLE
7.1
Insertion de lignes
INSERT INTO NomTable [ ( NomColonne [, ...] ) ]
{ DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) | requête }
Si aucune colonne n’est spécifiée les valeurs sont affectées aux colonnes dans l’ordre déterminée par la structure.
Vous pouvez donc soit créer une ligne ayant les valeurs par défaut, soit créer une ligne en donnant explicitement
les valeurs, soit remplir la table avec le résultat d’une requête.
On peut aussi remplir une table avec des données contenues dans un fichier.
COPY NomTable FROM ’chemin/nomfichier ’
copy essaitable from ’/Users/alain/Documents/basesdedonnees/donnees.txt’;
Les données dans le fichier sont séparées par des tabulations, sans autres délimiteurs.
7.2
Modification de lignes
UPDATE [ ONLY ] NomTable SET NomColonne = { expression | DEFAULT } [, ...]
[ WHERE condition ]
La mise à jour peut évidemment calculer une valeur à partir de la valeur actuellement dans la table.
update parcelles
set longueur=longueur-1
where noparcelle=1;
7.3
Suppression de lignes
DELETE FROM [ ONLY ] NomTable [ WHERE condition ]
Attention : la condition est facultative, mais sans condition, tous les enregistrements sont supprimés !!!
8
PRIVILÈGES
Le propriétaire d’une table peut attribuer aux autres utilisateurs, les droits (privilèges) d’utilisation de la table.
GRANT { { SELECT | INSERT | UPDATE | DELETE } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] NomTable [, ...]
TO { NomUtilisateur | GROUP NomGroupe | PUBLIC } [, ...]
De même, il peut retirer les droits sur une table à ces utilisateurs.
REVOKE [ GRANT OPTION FOR ]
{ { SELECT | INSERT | UPDATE | DELETE } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] NomTable [, ...]
FROM { NomUtilisateur | GROUP NomGroupe | PUBLIC } [, ...]
December 11, 2006 à 22h02
10/39
December 11, 2006 à 22h02
Il existe aussi des droits ou privilèges pour une base de données (droit de création), pour des fonctions (droit
d’exécution),...
GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE dbname [, ...]
TO { username | GROUP groupname | PUBLIC } [, ...] [ WITH GRANT OPTION ]
Expérimentation 1.
1. Concevez le MCD de la base filmo. Concevez le script de création de la base (avec le logiciel analyseSI, par
exemple).
2. Créez votre base filmo.
Afin de nommer les bases avec une certaine organisation, faites suivre le nom de votre base par votre propre
nom. Exemple :
create database filmo_terlutte;
3. Créez les tables avec leurs clés primaires, clés étrangères et autres contraintes.
4. Ajoutez quelques éléments dans chacune des tables.
5. Vérifiez auprès de votre voisin le nom de sa base de données. Connectez-vous à sa base. Essayez de consulter
les différentes tables.
6. Demandez qu’il vous donne les droits de consulter et de modifier mais ni d’ajouter, ni de supprimer des lignes
dans ses tables.
7. Faites quelques modifications de lignes.
9
TRANSACTION
Toutes les commandes qui agissent sur le contenu d’une base sont “dangereuses” ; certaines sont irréversibles. Il est
prudent de réaliser ses instructions à l’intérieur d’une transaction.
Une transaction permet de regrouper une suite d’instructions pour la considérer comme une instruction élementaire.
Les transactions permettent aussi de gérer les conflits.
Une transaction commence par l’instruction
START TRANSACTION
ou par
BEGIN
et se termine par
COMMIT
si vous voulez valider la transaction ou
ROLLBACK
si vous voulez annuler la transaction.
Expérimentation 2.
December 11, 2006 à 22h02
11/39
December 11, 2006 à 22h02
1. Connectez-vous à votre base filmo
2. Commencez une transaction.
3. Ajoutez quelques éléments dans une des tables (la table rayons par exemple).
4. Affichez le contenu de la table.
5. Terminez la transaction par la commande Rollback.
6. Affichez de nouveau le contenu de la table.
7. Recommencez la transaction mais terminez par Commit.
8. Affichez le contenu de la table.
10
10.1
CONFLITS
Présentation des conflits possibles
Pour comprendre comment les transactions permettent de gérer les conflits, regardons les différents cas d’accès concurrents à une même information qui provoquent des conflits.
Il faut imaginer deux personnes travaillant sur la même base de données.
10.1.1
Lecture inconsistante
T1
T2
update enregistrement
select enregistrement
rollback
Premier cas de conflit, l’utilisateur T2 met à jour un enregistrement. L’utilisateur T1 lit l’enregistrement. Mais
l’utilisateur T2 annule sa modification.
L’utilisateur T1 a donc lu une information qui n’a pas été validée.
10.1.2
Lecture non répétitive
T2
T1
select enregistrement 1
(consultation)
select enregistrement 2
(consultation)
update enregistrement 1
update enregistrement 1
Deuxième cas de conflit, l’utilisateur T1 consulte un enregistrement, puis un autre afin de savoir lequel modifier.
Il choisit de modifier l’enregistrement 1.
December 11, 2006 à 22h02
12/39
December 11, 2006 à 22h02
Mais, après qu’il ait lu les informations et avant qu’il ne fasse sa modification, l’utilisateur T2 modifie l’enregistrement 1.
L’utilisateur T1 modifie donc un enregistrement qui n’est pas celui qu’il a lu ; peut-être même, l’enregistrement ne
vérifie plus les raisons pour lesquelles l’utilisateur T1 l’avait choisi.
10.1.3
Lignes fantômes
T2
T1
select enregistrement 1
(sommation)
select enregistrement 2
(sommation)
select enregistrement 3
(sommation)
update enregistrement 2
delete enregistrement 3
delete enregistrement 4
update enregistrement 5
insert enregistrement 6
select enregistrement 5
(sommation)
select enregistrement 6
(sommation)
Autre cas de conflit, l’utilisateur T1 commence une consultation d’une série d’enregistrements dans le but de faire
un calcul sur l’ensemble de la série (par exemple, une sommation),
Mais, pendant qu’il effectue son parcours , l’utilisateur T2 modifie des enregistrements : il en modifie, en supprime,
en ajoute. Il est clair que l’utilisateur T1 ne fera pas son calcul sur les enregistrements qui existaient au début du
calcul.
Au début du calcul, les enregistrements corrects sont les enregistrements 1, 2, 3, 4 et 5. Mais il ne verra pas
l’enregistrement 4 qui est supprimé entre temps et il verra l’enregistrement 6 qui est ajouté ; de plus, l’enregistrement 3
est supprimé et les enregistrements 2 et 5 sont modifiés.
10.2
Outils de gestion des conflits
Pour assurer que l’utilisateur T1 effectue des instructions cohérentes, il faut qu’il puisse verrouiller les enregistrements
sur lesquels il veut travailler. Une solution serait de verrouiller complètement la table, c’est à dire d’interdir l’accès à
cette table pendant qu’on travaille dessus. Mais cela serait au dépend de l’efficacité.
Il existe donc différents niveaux de verrouillage.
verrou partagé (shared lock) utilisé pour lire un enregistrement. Les autres utilisateurs peuvent lire l’enregistrement
et peuvent poser le même type de verrou sur cet enregistrement. Mais il ne peuvent pas poser un autre type de
verrou.
verrou exclusif (exclusive lock) utilisé pour modifier un enregistrement. Les autres utilisateurs ne peuvent pas
lire l’enregistrement et ne peuvent poser aucun verrou sur l’enregistrement.
verrou global (global lock) utilisé pour bloquer une série d’enregistrements. Les autres utilisateurs ne peuvent pas
lire la série d’enregistrements et ne peuvent poser aucun verrou sur la série.
10.3
Solutions aux conflits
L’utilisation des verrous permet d’apporter des solutions aux conflits. Il s’agit de trouver le meilleur verrou à appliquer
pour éviter un problème sans gêner abusivement les autres utilisateurs.
December 11, 2006 à 22h02
13/39
December 11, 2006 à 22h02
10.3.1
Solution à la lecture inconsistante
Pour éviter la lecture inconsistante, l’utilisateur T2 devrait verrouiller l’enregistrement qu’il pense modifier afin
qu’aucun autre utilisateur ne risque de lire une information erronée.
T1
T2
verrou exclusif sur enregistrement
update enregistrement
attente enregistrement
...
rollback
select enregistrement
En posant un verrou exclusif, l’utilisateur T2 protège les autres utilisateurs contre des lectures inconsistantes.
L’enregistrement est libéré à la fin de la transaction.
10.3.2
Solution à la lecture non répétitive
Vous pouvez vérifier que si l’utilisateur T2 pose un verrou exclusif sur l’enregistrement, l’utilisateur T1 n’est pas
protégé contre la lecture non répétitive. Ici c’est l’utilisateur T1 qui doit se protéger contre ce problème. On voit donc
que l’utilisation des verrous constitue une stratégie que tous les utilisateurs doivent respecter.
Si l’utilisateur T1 veut garantir qu’un enregistrement ne changera pas de valeur, il doit le verrouiller. Il peut le
faire de telle façon que les autres puissent lire mais pas modifier l’enregistrement.
T1
T2
verrou partagé sur enregistrement 1
select enregistrement 1
verrou partagé sur enregistrement 2
select enregistrement 2
attente verrou exclusif sur enregistrement 1
....
update enregistrement 1
commit
verrou exclusif sur enregistrement 1
update enregistrement 1
commit
En posant un verrou partagé, l’utilisateur T1 protège l’accès à l’enregistrement 1 ; il autorise la lecture de
l’enregistrement mais interdit sa modification.
10.3.3
Solution aux lignes fantômes
Dans le cas d’un traitement qui nécessite la cohérence d’une série d’enregistrements, l’utilisateur doit verrouiller la
totalité de la série.
December 11, 2006 à 22h02
14/39
December 11, 2006 à 22h02
T1
T2
verrou global
select enregistrement 1
(sommation)
select enregistrement 2
(sommation)
select enregistrement 3
(sommation)
attente verrou exclusif sur enregistrement 2
...
select enregistrement 4
(sommation)
select enregistrement 5
(sommation)
verrou exclusif sur enregistrement 2
update enregistrement 2
verrou exclusif sur enregistrement 3
delete enregistrement 3
...
L’utilisateur T1 pose un verrou sur la totalité de la table ; aucun autre utilisateur ne peut modifier les enregistrements concernés.
10.4
Modes de transaction
Le langage SQL propose quatre modes d’isolation qui permettent d’éviter les cas de conflits que nous venons de voir.
La théorie définit
READ UNCOMMITTED aucun verrou
READ COMMITTED toute transaction qui désire modifier un enregistrement acquiert un verrou exclusif sur celui-ci,
jusqu’à la fin de ladite transaction.
REPEATABLE READ la transaction acquiert des verrous partagés sur tous les enregistrements lus.
SERIALIZABLE verrou global (souvent par blocs d’enregistrements).
niveau d’isolation
read uncommitted
read committed
repeatable read
serializable
lecture inconsistante
possible
impossible
impossible
impossible
lecture non répétitive
possible
possible
impossible
impossible
lignes fantômes
possible
possible
possible
impossible
Evidemment, le mode serializable est le plus protégé, mais il interdit les accès concurrents.
PostgreSQL n’utilise que deux niveaux d’isolation et les traite d’une façon particulière.
READ COMMITTED
La transaction voit des copies de la base prises au début des requêtes. Ces copies contiennent les modifications
effectuées par des transactions qui se sont terminées par commit. C’est le fonctionnement par défaut.
Deux requêtes successives peuvent donc afficher des résultats différents si des transactions ayant modifié les enregistrements se sont terminées par commit.
Pour résumer, vous pouvez lire les données mais vous n’êtes pas sûrs qu’elles ne seront pas modifiées à la prochaine
lecture. Mais si vous voulez lire les données, autant lire leurs mises à jour.
SERIALIZABLE
December 11, 2006 à 22h02
15/39
December 11, 2006 à 22h02
La transaction voit les enregistrements effectivement modifiés (et validés par un commit) avant le début de la
transaction. PostgreSQL essaiera de réaliser les différentes transactions concurrentes. Mais il est possible que des
modifications soient impossibles parce que d’autres transactions impliquant les mêmes enregistrements auront été
validées par commit.
Pour résumer, vous accédez aux données prises au début de la transaction. Pendant des transactions concurrentes,
chacun voit ses modifications. Si vous modifiez l’enregistrement A pendant qu’une transaction concurrente modifie
l’enregistrement B, postgreSQL synchronisera les deux transactions. A la fin des transactions, les enregistrements
A et B seront modifiés. Mais si vous essayez de modifier un enregistrement qu’une autre transaction (pas forcément
serializable) a déjà modifié, vous êtes bloqué en attendant le rollback ou le commit du concurrent. Si la transaction
concurrente valide sa modification, un message vous indiquera que la transaction a échoué. Dans ce cas, toute votre
transaction doit être annulée.
READ UNCOMMITTED est traité comme READ COMMITTED
REPEATABLE READ est traité comme SERIALIZABLE.
Vous définissez le mode d’isolation lors de la commande de début de transaction.
START TRANSACTION
[ ISOLATION LEVEL { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE } ]
[ READ WRITE | READ ONLY ]
La commande set transaction précise les caractéristiques des transactions suivantes qui commencent par begin.
SET TRANSACTION
[ ISOLATION LEVEL { READ COMMITTED | SERIALIZABLE } ]
[ READ WRITE | READ ONLY ]
Expérimentation 3.
1. Ouvrez deux terminaux.
2. Connectez-vous à votre base filmo dans les deux.
3. Créez une table essai avec un seul champ entier .
create table essai (e int);
4. Exécutez les commandes suivantes en respectant la chronologie.
dans le terminal 1
dans le terminal 2
insert into essai values (1);
insert into essai values (2);
insert into essai values (3);
insert into essai values (4);
insert into essai values (5);
insert into essai values (6);
insert into essai values (7);
select * from essai;
Constat.
5. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level read committed;
start transaction isolation level read committed;
update essai set e=11 where e=1;
select * from essai;
select * from essai;
update essai set e=22 where e=2;
select * from essai;
select * from essai;
commit;
select * from essai;
select * from essai;
commit;
December 11, 2006 à 22h02
16/39
December 11, 2006 à 22h02
Constat : chacun voit ses modifications. Il voit celles des autres lorsqu’elles sont validées par commit.
6. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level serializable;
start transaction isolation level serializable;
update essai set e=33 where e=3;
update essai set e=44 where e=4;
select * from essai;
select * from essai;
commit;
select * from essai;
select * from essai;
commit;
select * from essai;
Constat : chacun voit ses modifications. Mais il voit celles des autres seulement lorsque les validations par
commit sont faites. PostgreSQL effectue les deux modifications parce qu’elles portent sur des enregistrements
différents.
7. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level serializable;
start transaction isolation level serializable;
update essai set e=55 where e=5;
select * from essai;
select * from essai;
update essai set e=555 where e=5;
commit;
rollback;
Constat : le terminal 1 va être bloqué en attente soit de commit, soit de rollback. Si terminal 2 valide sa
modification par commit, terminal 1 ne peut qu’annuler la sienne.
8. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level serializable;
start transaction isolation level serializable;
update essai set e=66 where e=6;
select * from essai;
select * from essai;
update essai set e=666 where e=6;
rollback;
rollback;
Constat : Sa modification passera si terminal 2 invalide la sienne.
9. Continuez
dans le terminal 1
start transaction isolation level read committed;
dans le terminal 2
start transaction isolation level serializable;
select * from essai;
update essai set e=77 where e=7;
select * from essai;
update essai set e=777 where e=7;
commit;
select * from essai;
commit;
select * from essai;
December 11, 2006 à 22h02
17/39
December 11, 2006 à 22h02
Constat : terminal 2 va être bloqué. Après déblocage par le commit, il ne pourra pas continuer ses modifications.
Et même son commit sera remplacé par rollback.
10. Pour bien comprendre la différence
dans le terminal 1
delete from essai;
insert into essai values (1);
insert into essai values (2);
insert into essai values (3);
start transaction isolation level read committed;
dans le terminal 2
start transaction isolation level read committed;
select * from essai;
update essai set e=11 where e=1;
update essai set e=222 where e=2;
select * from essai;
select * from essai;
update essai set e=333 where e=3;
update essai set e=33 where e=3;
commit;
select * from essai;
commit;
Constat : chacun travaille sur sa copie. Le terminal 1 va être bloqué lorsqu’il accédera au même enregistrement
qu’une transaction concurrente. Après déblocage par le commit, il voit tout de suite les modifications.
Les données lues peuvent être modifiées à tout moment.
Et recommencez avec l’autre mode de transaction.
dans le terminal 1
delete from essai;
insert into essai values (1);
insert into essai values (2);
insert into essai values (3);
start transaction isolation level serializable;
dans le terminal 2
start transaction isolation level serializable;
select * from essai;
insert into essai values (7);
insert into essai values (8);
update essai set e=11 where e=1;
update essai set e=222 where e=2;
select * from essai;
select * from essai;
update essai set e=333 where e=3;
update essai set e=33 where e=3;
commit;
rollback;
Constat : chacun travaille sur sa copie. Le terminal 1 va être bloqué lorsqu’il accédera au même enregistrement
qu’une transaction concurrente. Après déblocage par le commit, il ne peut plus qu’annuler toutes ses modifications.
11. Pour vraiment bien comprendre la différence entre la théorie et la pratique.
December 11, 2006 à 22h02
18/39
December 11, 2006 à 22h02
dans le terminal 1
delete from essai;
insert into essai values (1);
insert into essai values (2);
insert into essai values (3);
start transaction isolation level serializable;
dans le terminal 2
start transaction isolation level serializable;
select * from essai;
select * from essai;
select sum(e) from essai;
insert into essai values (7);
delete from essai where e=2;
select * from essai;
select * from essai;
commit;
select * from
select sum(e)
commit;
select sum(e)
select * from
essai;
from essai;
from essai;
essai;
Constat : le mode serializable évite-t-il le problème des lignes fantômes ?
Selon moi, non ! Le mode serializable devrait garantir qu’aucune intervention sur les éléments consultés
ne puisse être validée pendant la transaction. Certains logiciels l’interprètent ainsi (SQL Anywhere Studio, par
exemple).
Mais cette interprétation du mode serializable se fait au dépend de l’efficacité. Et bon nombre de logiciels
interprètent le problème des lignes fantômes par la condition suivante : deux requêtes successives de la transaction
ne doivent pas donner des résultats différents. PostgreSQL vérifie bien cette condition... même si à l’issue de la
transaction, les résultats n’ont aucune pertinence puisque la base de données a été modifiée.
10.5
Conclusion
Faites des transactions courtes et faites des transactions correspondant à vos besoins.
N’oubliez pas qu’avec PostgreSQL, une transaction s’exécute sur une copie de la base de données.
Utilisez le verrouillage explicite de tables si votre intervention sur la base nécessite absolument que les données ne
puissent être modifiées pendant votre action.
11
VERROUILLAGE EXPLICITE
Comme vous avez pu le constater, des conflits persistent. Dans certaines situations, il faut garantir que l’on possède
un accès exclusif à une table (pour en modifier la structure, par exemple).
Il est possible de verrouiller explicitement une table par la commande
LOCK [ TABLE ] NomTable [, ...] [ IN ModeVerrou MODE ] [ NOWAIT ]
avec ModeVerrou qui peut prendre les valeurs suivantes :
ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
| SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
Le verrouillage se fera pour la transaction, après résolution des éventuels conflits.
L’option NoWait, comme son nom l’indique, n’attend pas. Mais si la table n’est pas disponible, la commande sera
annulée et un message d’erreur sera reçu.
Quelques mode de verrouillage :
December 11, 2006 à 22h02
19/39
December 11, 2006 à 22h02
ACCESS SHARE : l’accès est partagé. C’est le mode à utiliser pour lire des enregistrements. Ce mode rentrera en
conflit uniquement avec une transaction en access exclusive.
SHARE : Ce mode protège contre les changements de données par d’autres transactions. Il rentrera en conflit
avec les transactions en row exclusive, share update exclusive, share row exclusive, exclusive et access
exclusive.
ACCESS EXCLUSIVE : Ce mode ne permet aucune autre transaction. Il rentrera en conflit avec tout mode de
verrouillage posé sur cette table.
Expérimentation 4.
1. Ouvrez deux terminaux.
2. Connectez-vous à votre base filmo dans les deux.
3. Créez une table essai avec un seul champ entier .
create table essai (e int);
4. Exécutez les commandes suivantes en respectant la chronologie.
dans le terminal 1
insert into essai values (1);
insert into essai values (2);
dans le terminal 2
Constat.
5. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level read committed;
start transaction isolation level read committed;
lock essai in access share mode;
insert into essai values (3);
lock essai in access share mode;
insert into essai values (4);
insert into essai values (5);
select * from essai;
select * from essai;
commit;
commit;
Constat : chacun a accès à la table.
6. Continuez
dans le terminal 1
dans le terminal 2
start transaction isolation level read committed;
start transaction isolation level read committed;
lock essai in access share mode;
insert into essai values (6);
lock essai in share mode;
insert into essai values (7);
commit;
commit;
Constat : blocage de terminal 1.
7. Continuez
December 11, 2006 à 22h02
20/39
December 11, 2006 à 22h02
dans le terminal 1
dans le terminal 2
start transaction isolation level read committed;
start transaction isolation level read committed;
lock essai in access share mode;
insert into essai values (8);
lock essai in access exclusive mode;
commit;
start transaction isolation level read committed;
lock essai in access share mode;
insert into essai values (9);
commit;
select * from essai;
commit;
Constat : terminal 2 bloquera dans un premier temps pour obtenir l’accès. Une fois obtenu, il interdit l’accès
aux autres.
Le verrouillage d’enregistrements est réalisé par la commande SELECT, telle qu’elle a été présentée pour la sélection/affichage, à laquelle on ajoute la clause FOR UPDATE.
SELECT ........FROM .........
FOR UPDATE [ OF NomTable [, ...] ] [ NOWAIT ]
Les enregistrements sélectionnés par cette commande seront verrouillés pour éviter toute tentative de modification ou suppression par d’autres transactions. Cette commande se met en attente de libération de verrou si les
enregistrements sont déjà verrouillés par une autre transaction.
La commande peut spécifier une clause FOR TABLE de sorte que seuls les enregistrements de cette table seront
verrouillés même si la requête porte sur des enregistrements d’autres tables aussi.
Bien sûr, la commande n’est valide que si elle désigne bien des enregistrements. Particulièrement, SELECT FOR
UPDATE ne fonctionnera pas avec des agrégats (GROUP BY).
11.1
Conclusion
Faites des transactions courtes.
Verrouillez les tables si vous avez besoin de garantir la permanence de toutes les données sur lesquelles vous
travaillez.
Verrouillez uniquement les enregistrements si vous avez besoin de garantir simplement la permanence de l’enregistrement
sur lequel vous travaillez.
Libérez les tables dès que leur verrouillage n’est plus nécessaire.
12
COMMENTAIRES EN SQL
Des commentaires peuvent être écrits entre /* et */ dans un script SQL.
13
DEFINITION DE FONCTIONS SQL
Les fonctions SQL sont une suite d’instructions qui retourne un résultat (qui peut être vide).
La fonction possède des paramètres dont on indique simplement le type. Ils seront référencés par $1, $2... dans la
fonction.
Les instructions effectuent des actions. Le résultat de la dernière instruction définit le résultat de la fonction. C’est
évidemment au concepteur de la fonction de faire la correspondance entre cette instruction et le résultat.
La fonction peut renvoyer un ensemble de lignes (setof type).
December 11, 2006 à 22h02
21/39
December 11, 2006 à 22h02
CREATE FUNCTION NomFonction (types ) RETURNS type AS $$
instructions
$$ LANGUAGE sql;
Attention, c’est la syntaxe de postgreSQL 8.1 ; dans les versions précédentes, le texte de la fonction doit être entre
apostrophes... ce qui oblige à doubler les apostrophes quand la fonction contient une valeur date ou texte.
On a les instructions suivantes pour changer ou pour supprimer une fonction :
CREATE OR REPLACE FUNCTION NomFonction (types ) RETURNS type AS $$
instructions
$$ LANGUAGE sql;
DROP FUNCTION NomFonction (types ) [ CASCADE | RESTRICT ]
Voici quelques exemples de fonctions (que vous pouvez essayer) :
CREATE FUNCTION addition(integer, integer) RETURNS integer AS $$
SELECT $1 + $2 AS resultat;
$$ LANGUAGE SQL;
SELECT addition(1, 2) AS reponse;
\c crash
CREATE FUNCTION capacitetotale() RETURNS integer AS $$
BEGIN
SELECT sum(capacite) AS RESULT from salles ;
END;
$$ LANGUAGE sql;
SELECT capacitetotale() - capacite FROM salles;
Une fonction qui fait une action sans renvoyer de résultat peut être définie avec un type de résultat void.
\c filmo
CREATE FUNCTION AjoutVente (integer, integer, integer) RETURNS void AS $$
UPDATE BilletsVendus
SET nombre = nombre + $3
WHERE idfseance = $1 and codetarif = $2;
$$ LANGUAGE SQL;
SELECT AjoutVente(1, 2, 5);
ajoute 5 places vendues à la séance dont l’identifiant est 1 et du tarif dont le code est 2.
December 11, 2006 à 22h02
22/39
December 11, 2006 à 22h02
create or replace function programme() returns setof record as ’
select titre ,jour
from films, seances
where films.idffilm=seances.idffilm;
’ language sql;
select * from programme() as (film varchar(30),jour date);
CREATE TYPE ProgrammeJour AS (titrefilm varchar(50), horairefilm time);
create or replace function programme(date) returns setof ProgrammeJour as ’
select titre ,horaire
from films, seances
where films.idffilm=seances.idffilm
and jour=$1;
’ language sql;
select * from programme(’2006/11/28’) ;
Expérimentation 5.
1. Une fonction permettra de ne pas réécrire un calcul fréquemment utilisé.
Sachant que l’expression pour ajouter une durée numérique à un horaire de type time suit la syntaxe
horaire + (ValeurNumerique*interval ’1 hour’)
créez une fonction qui possède deux paramètres (l’horaire de début et la durée) et renvoie l’horaire de fin.
Testez-la !
CREATE FUNCTION HeureFin(time, numeric) RETURNS time AS ’
SELECT $1 + ($2*interval ”1 hour”) as result;
’ LANGUAGE SQL;
select seances.jour,seances.horaire, HeureFin(seances.horaire,films.duree)
from seances,films
where seances.idffilm=films.idffilm;
S’il existe des films qui sont programmés à une heure tardive, que constatez-vous pour l’affichage de l’horaire de
fin ? S’il n’en existe pas, ajoutez une séance vers 23h30 et testez votre fonction.
2. Une fonction peut être utile pour décomposer un problème. Sur la base de données crash, répondez à la question
"Quel est le nom du conférencier qui a fait le plus de conférences" en utilisant des fonctions.
December 11, 2006 à 22h02
23/39
December 11, 2006 à 22h02
CREATE TYPE ConfNbConf AS (nom varchar(60), nb bigint);
create or replace function NbConference() returns setof ConfNbConf as ’
select nomeco ,count(codeexpose)
from economistes,exposes
where codeeco=refconf
group by nomeco;
’ language sql;
create or replace function MaxConf() returns bigint as ’
select max(nb)
from NbConference();
’ language sql;
select nomeco
from economistes,exposes
where codeeco=refconf
group by nomeco
having count(codeexpose)=maxconf();
3. Sachant que la salle de cinéma contient 200 places, écrire une fonction qui calcule le nombre de places restantes
pour une séance donnée en paramètre.
Procédez par étapes
• Afficher les séances et le nombre de places vendues.
select idfseance,sum(nombre) from BilletsVendus group by IdfSeance;
• Ecrire une fonction pour afficher les places vendues d’une séance.
CREATE FUNCTION NbVendus(integer) RETURNS bigint AS ’
select sum(nombre) as resultat from BilletsVendus where IdfSeance = $1 ;
’ LANGUAGE SQL;
select idfseance, nbvendus(idfseance) from seances;
• Terminer par la fonction demandée.
CREATE OR REPLACE FUNCTION NbRestantes(integer) RETURNS bigint AS ’
SELECT 200 - (select sum(nombre) from BilletsVendus where IdfSeance = $1) as resultat;
’ LANGUAGE SQL;
ou
CREATE OR REPLACE FUNCTION NbRestantes(integer) RETURNS bigint AS ’
SELECT 200 - VentesFilm.nbvendus as resultat
from (select sum(nombre) as nbvendus
from BilletsVendus where IdfSeance = $1) as VentesFilm;
’ LANGUAGE SQL;
select idfseance, nbrestantes(idfseance) from seances;
Testez-la !
December 11, 2006 à 22h02
24/39
December 11, 2006 à 22h02
A partir d’ici, ce sont des prises de notes non rédigées
14
PROGRAMMATION EN PLPGSQL
Pour utiliser le langage PLPGSQL, exécuter les trois commandes décrites dans la doc PostgreSQL, page 645.
CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
’$libdir/plpgsql’ LANGUAGE C;
CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
’$libdir/plpgsql’ LANGUAGE C;
CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
HANDLER plpgsql_call_handler
VALIDATOR plpgsql_validator;
Ces commandes doivent être exécutées une fois dans chaque base de données pour laquelle on veut utiliser
PLPGSQL.
Le langage est interprété. Ceci signifie que les erreurs se remarquent à l’exécution. On peut passer dans une partie
d’alternative sans erreur alors qu’une autre partie est erronée.
14.1
Commentaires en PLpgSQL
– pour un commentaire de fin de ligne
/* bloc de commentaires */
14.2
Déclarations de fonctions
CREATE FUNCTION NomFonction (parametres ) RETURNS type AS $$
DECLARE
déclarations
BEGIN
instructions
RETURN resultat ;
END;
$$ LANGUAGE plpgsql;
L’emploi de $$ comme délimiteur de chaîne permet d’imbriquer plus facilement les chaînes en indiquant un label
entre les $. Ce qui donne
CREATE FUNCTION NomFonction (parametres ) RETURNS type AS $LabelFonction $
DECLARE
déclarations
BEGIN
RETURN quantity;
END;
$LabelFonction $ LANGUAGE plpgsql;
December 11, 2006 à 22h02
25/39
December 11, 2006 à 22h02
Si la fonction renvoie un résultat unique on emploie la commande RETURN expression; Si la fonction est censée
renvoyer un ensemble de lignes, elle contiendra une itération sur la commande RETURN NEXT expression; et se
terminera par un RETURN sans argument.
En général, les fonctions qui construisent un ensemble de lignes sont utilisées comme des tables.
SELECT * FROM some_func();
On peut définir des blocs délimités par BEGIN et END qui permettront de traiter les erreurs par une section
EXCEPTION.
14.3
Suppression des fonctions
DROP FUNCTION nomfunc(typeparametres);
14.4
syntaxe des déclarations:
name [ CONSTANT ] type [ NOT NULL ] [ { DEFAULT | := } expression ];
exemples :
quantity numeric;
qx integer := 10;
Dans les versions antérieures, pour les paramètres, on ne mettait que les types et les paramètres étaient ensuite
nommés $1, $2... Mais on peut faire directement
CREATE FUNCTION nomfunc(nomparam nomtype, nomparam nomtype) RETURNS type AS $$
on peut faire des appels de fonctions avec des paramètres passés par variables
CREATE FUNCTION sum_n_product(x int, y int, OUT sum int, OUT prod int) AS $$
Pour info, cela revient à faire un RETURNS record.
On peut utiliser des paramètres de type table. A l’exécution, la variable prendra la valeur de chaque ligne.
Exemple
CREATE FUNCTION augm(unesalle salles) RETURNS integer AS $$
BEGIN
IF unesalle.capacite<100 THEN
RETURN 3;
ELSE
RETURN 2;
END IF
END;
$$ LANGUAGE plpgsql;
select augm(salles)*capacite from salles;
December 11, 2006 à 22h02
26/39
December 11, 2006 à 22h02
aura pour effet d’afficher les capacités des salles multipliées par 2 ou 3 selon qu’elles sont inférieures à 100.
On peut déclarer des variables en copiant le type d’autres variables, particulièrement utile pour une variable du
type d’un champ de table.
VariableADéfinir VariableDéfinie%TYPE
On peut déclarer des variables de type "composite", type ligne de table
VariableADéfinir NomTable%ROWTYPE
Changement de nom de variables (à éviter ?? on peut utiliser aussi ALIAS)
RENAME oldname TO newname;
14.5
évaluation des expressions
********** attention
Dans logfunc1, le précompilateur peut évaluer que NOW représente une constante de type texte, que la colonne de
la table est de type date et peut évaluer la constante tout de suite (avec la conversion texte/date). La valeur insérée
sera celle de la précompilation à chaque appel de fonction. L’instruction RETURN $$NOW$$ fournit bien la date
différente à chaque exécution, mais celle insérée dans la table est toujours la même !!!
CREATE FUNCTION logfunc1(logtxt text) RETURNS timestamp AS $f1$
BEGIN
INSERT INTO logtable VALUES (logtxt, $$NOW$$);
RETURN $$NOW$$;
END;
$f1$ LANGUAGE plpgsql;
Dans logfunc2, le précompilateur ne sait pas ce que deviendra la constante de type texte et conserve $$NOW$$
comme une chaîne de caractère qui sera évaluée plus tard. Pourquoi ???? puisque la variable est déclarée de type
timestamp !?!? L’interpréteur pourrait aussi l’évaluation/conversion tout de suite. Mystère !
CREATE FUNCTION logfunc2(logtxt text) RETURNS timestamp AS $f2$
DECLARE
curtime timestamp;
BEGIN
curtime := $$NOW$$;
INSERT INTO logtable VALUES (logtxt, curtime);
RETURN curtime;
END;
$f2$ LANGUAGE plpgsql;
14.6
Instructions
Ce qui n’est pas reconnu comme PLpgSQL est envoyé à l’interpréteur SQL.
14.7
Affectation
identificateur := expression ;
December 11, 2006 à 22h02
27/39
December 11, 2006 à 22h02
14.8
Selection dans table
SELECT INTO variable ExpressionsColonnes FROM ...;
ExpressionsColonnes représente les colonnes comme dans une commande SQL normale, et la suite de la commande
correspond à la syntaxe de la commande select.
Attention, il existe une commande SELECT INTO en SQL qui crée une table. Pour créer une table, il faudrait
faire CREATE TABLE AS SELECT...
L’instruction place la première ligne de la sélection dans la variable. Le résultat est NULL si aucune ligne n’est
sélectionnée. Cela peut se tester avec la condition IS NULL ou dans la variable booléenne FOUND. Il n’est pas possible
de déterminer si le résultat de la sélection contient plus d’une ligne.
14.9
Instruction générée dynamiquement
EXECUTE ChaîneCommande [ INTO variable ];
La chaîne de caractère peut être construite avec des résultats d’expressions. Par contre, on ne peut pas construire
une chaîne SELECT...INTO
Cette commande peut être utile pour exécuter une instruction qu’on veut absolument non précompilée
14.10
Instruction sans résultat
PERFORM requête ;
La syntaxe est la même que celle de SELECT en remplaçant SELECT par PERFORM. L’instruction ne produit
pas de résultat !?!? Ceci est utile pour des instructions ayant des effets de bord, par exemple, une commande SELECT
avec une fonction trigger.
14.11
Instruction vide
NULL;
14.12
Statut de l’exécution d’une commande
GET DIAGNOSTICS variable = item [ , ...
];
ou utiliser la variable booléenne FOUND.
14.13
IF
IF
IF
IF
IF
Alternatives
...THEN
... THEN
... THEN
... THEN
... THEN
...
...
...
...
ELSE
ELSE IF
ELSIF ... THEN ... ELSE
ELSEIF ... THEN ... ELSE
Les formes classiques
December 11, 2006 à 22h02
28/39
December 11, 2006 à 22h02
IF condition THEN
instructions
END IF;
IF condition THEN
instructions
ELSE
instructions
END IF;
Les alternatives imbriquées
IF condition THEN
instructions
[ ELSIF condition THEN
instructions
[ ELSIF condition THEN
instructions
...]]
[ ELSE
instructions ]
END IF;
ELSEIF is an alias for ELSIF.
14.14
Itérations
[ «label» ]
LOOP
instructions
END LOOP [ label ];
Cela définit une boucle infinie dont on sort par l’instruction EXIT ou RETURN. Le label permet d’indiquer quelle
boucle il faut arrêter.
EXIT [ label ] [ WHEN expression ];
si l’expression est vraie, la boucle indiquée par le label se termine ; sinon la boucle poursuit avec l’instruction
suivante.
CONTINUE [ label ] [ WHEN expression ];
On reprend l’itération si l’expression est vraie.
exemple :
LOOP
– some computations
EXIT WHEN count > 100;
CONTINUE WHEN count < 50;
– some computations for count IN [50 ..
END LOOP;
December 11, 2006 à 22h02
100]
29/39
December 11, 2006 à 22h02
EXIT et CONTINUE peuvent être utilisées avec toutes itérations.
[ «label» ]
WHILE condition LOOP
instructions
END LOOP [ label ];
[ «label» ]
FOR name IN [ REVERSE ] expression ..
instructions
END LOOP [ label ];
expression LOOP
La variable name sera de type INTEGER.
exemples :
FOR i IN 1..10 LOOP
– some computations here
RAISE NOTICE Ši is %Š, i;
END LOOP;
FOR i IN REVERSE 10..1 LOOP
– some computations here
END LOOP;
14.15
Itération dans une requête
[ «label» ]
FOR record_or_row IN query LOOP
instructions
END LOOP [ label ];
Chaque ligne sera affectée à la variable qui peut être de type RECORD pour simplifier.
CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS $func_cs$
DECLARE
mviews RECORD;
BEGIN
FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
– now "mviews" has one record from cs_materialized_views
....
END LOOP;
RETURN ...;
END;
$func_cs$ LANGUAGE plpgsql;
Si la boucle se termine par EXIT, la dernière ligne affectée est encore accessible.
December 11, 2006 à 22h02
30/39
December 11, 2006 à 22h02
[ «label» ]
FOR record_or_row IN EXECUTE text_expression LOOP
instructions
END LOOP [ label ];
Dans cette forme, la requête est réévaluée à chaque étape de l’itération.
14.16
Traitements des erreurs
[ «label» ]
[ DECLARE
declarations ]
BEGIN
instructions
EXCEPTION
WHEN condition [ OR condition ... ] THEN
handler_instructions
[ WHEN condition [ OR condition ... ] THEN
handler_instructions
... ]
END;
Si une erreur apparaît à l’exécution, la section EXCEPTION est exécutée. Si une condition est vérifiée, le traitement
correspondant est exécuté et l’exécution se poursuit après le END. Sinon l’erreur se propage à la suite.
Voir la documentation pour les codes d’erreurs.
14.17
Fonctions récursives
On peut écrire des fonctions récursives... Il suffit de bien maîtriser l’arrêt. Ici, une fonction qui parcourt un arbre,
codé par un systême père/fils, dans une table.
Voici la structure de la table
si_id int si_parentid int
1
2
1
3
2
4
2
5
1
6
5
7
5
8
5
si_item
Paper
Recycled
20 lb
40 lb
Non-Recycled
20 lb
40 lb
Scraps
CREATE FUNCTION cp_getitemfullname(int8) RETURNS varchar AS $fr$
DECLARE
itemid ALIAS FOR $1;
itemfullname varchar(255);
itemrecord RECORD;
BEGIN
SELECT s.* INTO itemrecord FROM supplyitem s where si_id=itemid;
itemfullname := itemfullname + itemrecord.si_item;
IF itemrecord.si_parentid IS NOT NULL THEN
itemfullname := cp_getitemfullname(itemrecord.si_parentid) + ”− >” + itemfullname ;
RETURN itemfullname;
ELSE
RETURN itemfullname;
END IF;
END$fr$ LANGUAGE ’plpgsql’
December 11, 2006 à 22h02
31/39
December 11, 2006 à 22h02
SELECT cp_getitemfullname(8)
This returns
Affichage Paper − > Non-Recycled − > Scraps
15
TRIGGERS
Un trigger spécifie qu’une fonction doit être exécutée lors de certaines commandes SQL : Insert, Update ou Delete.
Le trigger peut avoir une action au niveau de la ligne (per-row trigger) ou au niveau global (per-statement trigger).
Dans chaque catégorie, il peut être before ou after trigger.
On définit la fonction, puis on définit le trigger. La fonction ne peut pas être une fonction SQL ; il faut qu’elle soit
écrite dans un autre langage, comme plpgSQL, Perl, Python...
CREATE TRIGGER NomTrigger { BEFORE | AFTER } { evenement [ OR ...
ON NomTable [ FOR [ EACH ] { ROW | STATEMENT } ]
EXECUTE PROCEDURE NomFonction ( arguments )
] }
DROP TRIGGER NomTrigger ON table [ CASCADE | RESTRICT ]
L’événement peut être insert, update ou delete et il peut y en avoir plusieurs séparés par OR.
Un row-level before trigger doit renvoyer soit un résultat NULL, soit une ligne de table.
Si un row-level before trigger renvoie un résultat NULL, la commande n’est pas exécutée. S’il renvoie un résultat
ligne (en général la variable new ou old, éventuellement modifiée), la commande est exécutée avec cette ligne.
Les autres triggers devraient renvoyer NULL.
Les row before triggers servent à modifier des lignes insérées ou modifiées. Les row after trigger peuvent servir à
mettre à jour des tables liées.
un trigger possède des variables prédéfinies : NEW, OLD....
NEW est de type record et contient la nouvelle ligne pour les commandes INSERT et UPDATE
OLD est de type record et contient l’ancienne ligne pour les commandes UPDATE et DELETE
TG_NAME (type name) le nom du trigger
TG_WHEN (type texte) contient after ou before
TG_LEVEL (type texte) contient row ou statement
TG_OP (type texte) contient insert, update ou delete
TG_RELNAME (type name) contient le nom de la table
et quelques autres variables
Voici quelques exemples sur la base crash. Aucune salle n’étant de capacité supérieure à 300 places, on va corriger
une insertion erronée plutôt que de la refuser.
\c crash
create or replace function verif() returns trigger as $verifplus$
begin
if new.capacite > 300 then
new.capacite := 300;
raise notice ’capacité ramenée à 300’;
end if;
December 11, 2006 à 22h02
32/39
December 11, 2006 à 22h02
return new;
end;
$verifplus$ language plpgsql;
create trigger verifplus
before insert or update on salles
for each row execute procedure verif();
insert into salles values (’TR1’,’Labo Langue’,360);
select * from salles;
drop trigger verifplus on salles;
drop function verif();
Pour un row-level before trigger, si la fonction renvoie un résultat null, la commande Insert ou update n’est pas
exécutée.
Par exemple, la fonction ci-dessous renvoie un résultat null si la capacité est supérieure à 1000 et n’insérerait aucun
élément avec une telle capacité.
create or replace function verif() returns trigger as $verifplus$
begin
if new.capacite > 1000 then
raise notice ’insertion annulée, capacité trop grande’;
return null;
elsif new.capacite > 300 then
new.capacite := 300;
raise notice ’capacité trop grande, ramenée à 300’;
return new;
else
return new;
end if;
end;
$verifplus$ language plpgsql;
Expérimentation 6.
1. Supposons qu’à chaque fois qu’on ajoute un film, on ajoute une séance pour le lendemain
même à midi. Réalisez cette insertion d’une séance par un trigger.
create or replace function AjoutSeance() returns trigger as ’
begin
insert into seances
values((select max(idfseance) from seances) +1,current_date+1,”12:00:00”,new.idffilm);
return new;
end;
’ language plpgsql;
create trigger NouvelleSeance
after insert on films
for each row execute procedure AjoutSeance();
December 11, 2006 à 22h02
33/39
December 11, 2006 à 22h02
2. Sachant que la salle de cinéma contient 200 places, voici un trigger qui ne fait l’insertion ou la modification que
si le nombre de billets est inférieur à 200.
Testez-le !
create or replace function VerificationCapacite() returns trigger as ’
begin
if new.nombre >= 200 then
raise exception ”vente impossible, trop de billets”;
return null;
else
return new;
end if;
end;
’ language plpgsql;
create trigger tropventes
before insert or update on billetsvendus
for each row execute procedure VerificationCapacite();
insert into billetsvendus values (2,3,285);
Modifiez-le pour créer un trigger qui tient compte du nombre de places vendues pour la séance et ne fait l’insertion
ou la modification que si le nombre est acceptable.
Vous pouvez utiliser la fonction NbVendus déjà créée.
create or replace function VerificationCapacite() returns trigger as ’
begin
if new.nombre > 200-NbVendus(new.idfseance) then
raise exception ”vente impossible, trop de billets”;
return null;
else
return new;
end if;
end;
’ language plpgsql;
3. Voici une fonction qui examine si une séance est programmée un jour et n’est pas terminée. Si c’est le cas
l’insertion d’une nouvelle séance à l’horaire prévu n’est pas possible. Etudiez cette fonction
create function existant() returns trigger as ’
declare
res record;
begin
select count(*) as nb
into res
from seances,films
where seances.idffilm=films.idffilm
and seances.jour+seances.horaire <= new.jour+new.horaire
and seances.jour+seances.horaire+(films.duree*interval ”1 hour”)
> new.jour+new.horaire;
if res.nb=0 then
return new;
December 11, 2006 à 22h02
34/39
December 11, 2006 à 22h02
else
raise exception ”un film pas termine”;
return null;
end if;
end;
’ language plpgsql;
create trigger filmavant
before insert on seances
for each row execute procedure existant();
insert into seances values (2,’2006/09/29’,’21:45:00’,2);
affichera, s’il existe un film dont la séance est programmée le même jour et qui ne sera pas terminée,
ERROR: un film pas termine
ERROR: un film pas termine
Transformez la fonction pour qu’elle regarde aussi si la séance à ajouter ne se termine pas trop tard, c’est à dire
que l’heure de fin dépasse l’heure de début d’un film déjà programmé.
create or replace function existant() returns trigger as ’
declare
resavant record;
resapres record;
begin
select count(*) as nb
into resavant
from seances,films
where seances.idffilm=films.idffilm
and seances.jour+seances.horaire <= new.jour+new.horaire
and seances.jour+seances.horaire+(films.duree*interval ”1 hour”)
> new.jour+new.horaire;
select count(*) as nb
into resapres
from seances,films
where seances.idffilm=films.idffilm
and new.jour+new.horaire <= seances.jour+seances.horaire
and new.jour+new.horaire
+((select duree from films where idffilm=new.idffilm)*interval ”1 hour”)
> seances.jour+seances.horaire;
if resavant.nb<>0 then
raise exception ”un film pas termine”;
return null;
elsif resapres.nb<>0 then
raise exception ”trop long pour le film suivant”;
return null;
else
return new;
end if;
end;
’ language plpgsql;
Contents
1 INTERROGATION
December 11, 2006 à 22h02
1
35/39
December 11, 2006 à 22h02
2 FONCTIONS ET EXPRESSIONS
2.1 expressions arithmétiques . . . . .
2.2 expressions caractères . . . . . . .
2.3 expressions dates . . . . . . . . . .
2.4 expressions booléennes . . . . . . .
.
.
.
.
3
3
3
3
4
3 CREATION D’UTILISATEURS
3.1 Création de la base à partir du terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Création d’un utilisateur ou d’un groupe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4
4
4 CREATION DE BASE
4.1 Création de la base à partir du terminal
4.2 Création de la base . . . . . . . . . . . .
4.3 Renommage de la base . . . . . . . . . .
4.4 Suppression de la base . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
5
5
5
5 STRUCTURE DE TABLE
5.1 Types de données . . . . .
5.2 Création de table . . . . .
5.3 Modifications de table . .
5.4 Suppression de table . . .
5.5 Quelques exemples . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
6
7
8
8
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
6 INDEXATION
8
7 CONTENU D’UNE TABLE
7.1 Insertion de lignes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2 Modification de lignes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.3 Suppression de lignes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
10
10
10
8 PRIVILÈGES
10
9 TRANSACTION
11
10 CONFLITS
10.1 Présentation des conflits possibles . . . . .
10.1.1 Lecture inconsistante . . . . . . . .
10.1.2 Lecture non répétitive . . . . . . .
10.1.3 Lignes fantômes . . . . . . . . . .
10.2 Outils de gestion des conflits . . . . . . .
10.3 Solutions aux conflits . . . . . . . . . . . .
10.3.1 Solution à la lecture inconsistante
10.3.2 Solution à la lecture non répétitive
10.3.3 Solution aux lignes fantômes . . .
10.4 Modes de transaction . . . . . . . . . . . .
10.5 Conclusion . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
12
12
12
12
13
13
13
14
14
14
15
19
11 VERROUILLAGE EXPLICITE
11.1 Conclusion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
21
12 COMMENTAIRES EN SQL
21
13 DEFINITION DE FONCTIONS SQL
21
December 11, 2006 à 22h02
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
36/39
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
December 11, 2006 à 22h02
14 PROGRAMMATION EN PLPGSQL
14.1 Commentaires en PLpgSQL . . . . . .
14.2 Déclarations de fonctions . . . . . . .
14.3 Suppression des fonctions . . . . . . .
14.4 syntaxe des déclarations: . . . . . . .
14.5 évaluation des expressions . . . . . . .
14.6 Instructions . . . . . . . . . . . . . . .
14.7 Affectation . . . . . . . . . . . . . . .
14.8 Selection dans table . . . . . . . . . .
14.9 Instruction générée dynamiquement .
14.10Instruction sans résultat . . . . . . . .
14.11Instruction vide . . . . . . . . . . . . .
14.12Statut de l’exécution d’une commande
14.13Alternatives . . . . . . . . . . . . . . .
14.14Itérations . . . . . . . . . . . . . . . .
14.15Itération dans une requête . . . . . . .
14.16Traitements des erreurs . . . . . . . .
14.17Fonctions récursives . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
25
26
26
27
27
27
28
28
28
28
28
28
29
30
31
31
15 TRIGGERS
32
A Commandes PSQL
38
December 11, 2006 à 22h02
37/39
December 11, 2006 à 22h02
A
Commandes PSQL
Général
\?
\c[onnect] [NomBase |- [utilisateur ]]
\cd [répertoire ]
\h [nom ]
\q
\set [nom [valeur ]]
\unset nom
\! [commande ]
aide psql
connecte à une autre base de données
change de répertoire courant
aide-mémoire pour les commandes SQL, * pour toutes les commandes
quitte psql
initialise la variable interne ou les affiche toutes s’il n’y a aucun paramètre
désinitialise (supprime) la variable interne
exécute la commande dans un shell ou lance un shell interactif
Tampon de requête (concerne la dernière requête select)
\e [fichier ] édite le tampon de requête ou le fichier avec un éditeur externe (par ex, emacs)
\g [fichier ] envoie le tampon de requêtes au serveur (et les résultats au fichier ou | tube)
\p
affiche le contenu du tampon de requête
\r
efface le tampon de requêtes
\s [fichier ] affiche l’historique ou le sauvegarde dans un fichier
\w [fichier ] écrit le contenu du tampon de requêtes dans un fichier
Entrée/Sortie
\echo [texte ]
\i fichier
\o [fichier ]
\o
\qecho [texte ]
écrit un texte sur la sortie standard
exécute les commandes du fichier
écrit les résultats des requêtes et autres commandes dans un fichier (ou | tube)
termine la sortie dans fichier
écrit un texte sur la sortie pour les résultats des requêtes
Information
\d [nom ]
\d{t|i|s|v|S} [modèle ]
\da [modèle ]
\dc [modèle ]
\dC
\dd [modèle ]
\dD [modèle ]
\df [modèle ]
\dn [modèle ]
\do [modèle ]
\dl
\dp [modèle ]
\dT [modèle ]
\du [modèle ]
\l
\z [modèle ]
Formatage
\a
\C [chaîne ]
\f [chaîne ]
\H
\pset nom [valeur ]
\t
\T [chaîne ]
\x
December 11, 2006 à 22h02
décrit la table, l’index, la séquence ou la vue
liste les tables/index/séquences/vues/tables système (ajoutez "+" pour plus de détails)
affiche la liste des fonctions d’aggrégation
affiche la liste des conversions
affiche la liste des conversions explicites
affiche les commentaires pour un objet
affiche la liste des domaines
affiche la liste des fonctions (ajoutez "+" pour plus de détails)
affiche la liste des schémas
affiche la liste des operateurs
affiche la liste des objets larges
affiche la liste des privilèges d’accès aux tables
affiche la liste des types de données (ajoutez "+" pour plus de détails)
affiche la liste des utilisateurs
affiche toutes les bases de données (ajoutez "+" pour plus de détails)
affiche la liste des privilèges d’accès aux tables (identique à \dp)
bascule entre les modes de sortie aligné et non aligné
initialise le titre d’une table, ou initialise à rien si sans argument
affiche ou initialise le séparateur de champ pour une sortie non alignée des requêtes
bascule le mode de sortie HTML, avec des balises HTML
initialise les variables de sortie
(nom est format | border | expanded | fieldsep | footer | null | recordsep
| tuples_only | title | tableattr | pager )
affiche seulement les lignes, pas les titres des colonnes
initialise les attributs HTML de la balise <table>, ou l’annule si aucun argument
bascule l’affichage étendu (résultat affiché par ligne ou par fiche)
38/39
December 11, 2006 à 22h02
Le modèle est un masque utilisant des caractères spéciaux tels que ? pour remplacer un caractère quelconque et *
pour remplacer une suite de caractères. \dt ?a* affiche les tables qui possèdent un a en deuxième caractère.
December 11, 2006 à 22h02
39/39
December 11, 2006 à 22h02