| 1 |
<?xml version="1.0" encoding="ISO-8859-15"?> |
|---|
| 2 |
<!-- Dernière modification |
|---|
| 3 |
le $Date$ |
|---|
| 4 |
par $Author$ |
|---|
| 5 |
révision $Revision$ --> |
|---|
| 6 |
<!-- SAS : 20070311 --> |
|---|
| 7 |
|
|---|
| 8 |
<chapter id="tutorial-advanced"> |
|---|
| 9 |
<title>Fonctionnalités avancées</title> |
|---|
| 10 |
|
|---|
| 11 |
<sect1 id="tutorial-advanced-intro"> |
|---|
| 12 |
<title>Introduction</title> |
|---|
| 13 |
|
|---|
| 14 |
<para> |
|---|
| 15 |
Le chapitre précédant couvre les bases de l'utilisation |
|---|
| 16 |
de <acronym>SQL</acronym> pour le stockage et l'accès aux données avec |
|---|
| 17 |
<productname>PostgreSQL</productname>. Il est temps d'aborder |
|---|
| 18 |
quelques fonctionnalités avancées du <acronym>SQL</acronym> |
|---|
| 19 |
qui simplifient la gestion et empêchent la perte ou la corruption des |
|---|
| 20 |
données. Quelques extensions de <productname>PostgreSQL</productname> sont |
|---|
| 21 |
également abordées. |
|---|
| 22 |
</para> |
|---|
| 23 |
|
|---|
| 24 |
<para> |
|---|
| 25 |
Ce chapitre fait occasionnellement référence aux exemples disponibles dans le |
|---|
| 26 |
<xref linkend="tutorial-sql"/> pour les modifier ou les améliorer. Il est donc |
|---|
| 27 |
préférable d'avoir lu ce chapitre. Quelques exemples de ce |
|---|
| 28 |
chapitre sont également disponibles dans <filename>advanced.sql</filename> |
|---|
| 29 |
situé dans le répertoire du tutoriel. Ce fichier contient, de plus, quelques |
|---|
| 30 |
données à charger pour utiliser l'exemple. Cela n'est pas repris ici |
|---|
| 31 |
(on peut se référer à la <xref linkend="tutorial-sql-intro"/> pour savoir comment |
|---|
| 32 |
utiliser ce fichier). |
|---|
| 33 |
</para> |
|---|
| 34 |
</sect1> |
|---|
| 35 |
|
|---|
| 36 |
|
|---|
| 37 |
<sect1 id="tutorial-views"> |
|---|
| 38 |
<title>Vues</title> |
|---|
| 39 |
|
|---|
| 40 |
<indexterm zone="tutorial-views"> |
|---|
| 41 |
<primary>vue</primary> |
|---|
| 42 |
<secondary>view</secondary> |
|---|
| 43 |
</indexterm> |
|---|
| 44 |
|
|---|
| 45 |
<para> |
|---|
| 46 |
Se référer aux requêtes de la <xref linkend="tutorial-join"/>. |
|---|
| 47 |
Si la liste des enregistrements du temps et des villes est d'un |
|---|
| 48 |
intérêt particulier pour l'application considérée mais qu'il devient |
|---|
| 49 |
contraignant de saisir la requête à chaque utilisation, il est possible |
|---|
| 50 |
de créer une <firstterm>vue</firstterm> avec la requête. De ce fait, la |
|---|
| 51 |
requête est nommée et il peut y être fait référence de la même façon |
|---|
| 52 |
qu'il est fait référence à une table : |
|---|
| 53 |
|
|---|
| 54 |
<programlisting>CREATE VIEW ma_vue AS |
|---|
| 55 |
SELECT ville, t_basse, t_haute, prcp, date, emplacement |
|---|
| 56 |
FROM temps, villes |
|---|
| 57 |
WHERE ville = nom; |
|---|
| 58 |
|
|---|
| 59 |
SELECT * FROM ma_vue;</programlisting> |
|---|
| 60 |
</para> |
|---|
| 61 |
|
|---|
| 62 |
<para> |
|---|
| 63 |
L'utilisation des vues est un aspect clé d'une bonne |
|---|
| 64 |
conception des bases de données SQL. Les vues permettent |
|---|
| 65 |
d'encapsuler les détails de la structure des tables. Celle-ci peut |
|---|
| 66 |
alors changer avec l'évolution de l'application, tandis que l'interface reste |
|---|
| 67 |
constante. |
|---|
| 68 |
</para> |
|---|
| 69 |
|
|---|
| 70 |
<para> |
|---|
| 71 |
Les vues peuvent être utilisées dans quasiment toutes les situations |
|---|
| 72 |
où une vraie table est utilisable. Il n'est, de plus, pas |
|---|
| 73 |
inhabituel de construire des vues reposant sur d'autres vues. |
|---|
| 74 |
</para> |
|---|
| 75 |
</sect1> |
|---|
| 76 |
|
|---|
| 77 |
|
|---|
| 78 |
<sect1 id="tutorial-fk"> |
|---|
| 79 |
<title>Clés étrangères</title> |
|---|
| 80 |
|
|---|
| 81 |
<indexterm zone="tutorial-fk"> |
|---|
| 82 |
<primary>clé étrangère</primary> |
|---|
| 83 |
<secondary>foreign key</secondary> |
|---|
| 84 |
</indexterm> |
|---|
| 85 |
|
|---|
| 86 |
<indexterm zone="tutorial-fk"> |
|---|
| 87 |
<primary>intégrité référentielle</primary> |
|---|
| 88 |
<secondary>referential integrity</secondary> |
|---|
| 89 |
</indexterm> |
|---|
| 90 |
|
|---|
| 91 |
<para> |
|---|
| 92 |
Soient les tables |
|---|
| 93 |
<classname>temps</classname> et <classname>villes</classname> définies |
|---|
| 94 |
dans le <xref linkend="tutorial-sql"/>. |
|---|
| 95 |
Il s'agit maintenant de s'assurer que personne |
|---|
| 96 |
n'insère de ligne dans la table <classname>temps</classname> qui ne |
|---|
| 97 |
corresponde à une entrée dans la table <classname>villes</classname>. |
|---|
| 98 |
On appelle cela maintenir l'<firstterm>intégrité |
|---|
| 99 |
référentielle</firstterm> des données. Dans les systèmes de bases de |
|---|
| 100 |
données simplistes, lorsqu'au moins c'est possible, cela est parfois |
|---|
| 101 |
obtenu par la vérification préalable de l'existence d'un enregistrement |
|---|
| 102 |
correspondant dans la table <classname>villes</classname>, puis par |
|---|
| 103 |
l'insertion, ou l'interdiction, du nouvel enregistrement dans |
|---|
| 104 |
<classname>temps</classname>. Puisque cette approche, peu pratique, |
|---|
| 105 |
présente un certain nombre d'inconvénients, |
|---|
| 106 |
<productname>PostgreSQL</productname> peut se charger du maintien de |
|---|
| 107 |
l'<firstterm>intégrité référentielle</firstterm>. |
|---|
| 108 |
</para> |
|---|
| 109 |
|
|---|
| 110 |
<para> |
|---|
| 111 |
La nouvelle déclaration des tables ressemble alors à ceci : |
|---|
| 112 |
|
|---|
| 113 |
<programlisting>CREATE TABLE villes ( |
|---|
| 114 |
ville varchar(80) primary key, |
|---|
| 115 |
emplacement point |
|---|
| 116 |
); |
|---|
| 117 |
|
|---|
| 118 |
CREATE TABLE temps ( |
|---|
| 119 |
ville varchar(80) references villes, |
|---|
| 120 |
t_haute int, |
|---|
| 121 |
t_basse int, |
|---|
| 122 |
prcp real, |
|---|
| 123 |
date date |
|---|
| 124 |
);</programlisting> |
|---|
| 125 |
|
|---|
| 126 |
Lors d'une tentative d'insertion d'enregistrement non valide : |
|---|
| 127 |
|
|---|
| 128 |
<programlisting>INSERT INTO temps VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28');</programlisting> |
|---|
| 129 |
|
|---|
| 130 |
<screen>ERROR: insert or update on table "temps" violates foreign key constraint "temps_ville_fkey" |
|---|
| 131 |
DETAIL : Key (ville)=(a) is not present in table "villes".</screen> |
|---|
| 132 |
|
|---|
| 133 |
<!-- SAS 20061109 |
|---|
| 134 |
Pourquoi ne pas traduire les messages d'erreur ? |
|---|
| 135 |
<screen>ERROR: insert or update on table "temps" violates foreign key constraint "temps_ville_fkey" |
|---|
| 136 |
DETAIL: Key (ville)=(Berkeley) is not present in table "villes".</screen> |
|---|
| 137 |
--> |
|---|
| 138 |
</para> |
|---|
| 139 |
|
|---|
| 140 |
<!-- SAS 20080225 |
|---|
| 141 |
Clé secondaire ? --> |
|---|
| 142 |
<para> |
|---|
| 143 |
Le comportement des clés étrangères peut être adapté très finement à |
|---|
| 144 |
une application particulière. Ce tutoriel ne va pas plus loin que cet exemple simple. |
|---|
| 145 |
De plus amples informations sont accessibles dans le <xref linkend="ddl"/>. |
|---|
| 146 |
Une utilisation efficiente des clés étrangères améliore la |
|---|
| 147 |
qualité des applications accédant aux bases de données. Il est donc |
|---|
| 148 |
fortement conseillé d'apprendre à les utiliser. |
|---|
| 149 |
</para> |
|---|
| 150 |
</sect1> |
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 |
<sect1 id="tutorial-transactions"> |
|---|
| 154 |
<title>Transactions</title> |
|---|
| 155 |
|
|---|
| 156 |
<indexterm zone="tutorial-transactions"> |
|---|
| 157 |
<primary>transaction</primary> |
|---|
| 158 |
</indexterm> |
|---|
| 159 |
|
|---|
| 160 |
<para> |
|---|
| 161 |
Les <firstterm>transactions</firstterm> sont un concept fondamental de tous les |
|---|
| 162 |
systèmes de bases de données. Une transaction assemble plusieurs étapes |
|---|
| 163 |
en une seule opération tout-ou-rien. |
|---|
| 164 |
Les états intermédiaires entre les étapes ne sont pas visibles par les |
|---|
| 165 |
transactions concurrentes. De plus, si un échec survient qui empêche le |
|---|
| 166 |
succès de la transaction, alors aucune des étapes n'affecte la base |
|---|
| 167 |
de données. |
|---|
| 168 |
</para> |
|---|
| 169 |
|
|---|
| 170 |
<para> |
|---|
| 171 |
Si l'on considère, par exemple, la base de données d'une banque qui |
|---|
| 172 |
contient le solde de différents comptes clients et le solde total des |
|---|
| 173 |
dépôts par branches et que l'on veuille enregistrer un virement de |
|---|
| 174 |
100 euros du compte d'Alice vers celui de Bob, |
|---|
| 175 |
les commandes SQL peuvent ressembler à cela (après simplification) : |
|---|
| 176 |
|
|---|
| 177 |
<programlisting>UPDATE comptes SET balance = balance - 100.00 |
|---|
| 178 |
WHERE nom = 'Alice'; |
|---|
| 179 |
UPDATE branches SET balance = balance - 100.00 |
|---|
| 180 |
WHERE nom = (SELECT nom_branche FROM comptes WHERE nom = 'Alice'); |
|---|
| 181 |
UPDATE comptes SET balance = balance + 100.00 |
|---|
| 182 |
WHERE nom = 'Bob'; |
|---|
| 183 |
UPDATE branches SET balance = balance + 100.00 |
|---|
| 184 |
WHERE nom = (SELECT nom_branche FROM comptes WHERE nom = 'Bob');</programlisting> |
|---|
| 185 |
</para> |
|---|
| 186 |
|
|---|
| 187 |
<para> |
|---|
| 188 |
Ce ne sont pas les détails des commandes qui importent ici ; le point |
|---|
| 189 |
important est la nécessité de plusieurs mises à jour séparées pour |
|---|
| 190 |
accomplir cette opération assez simple. Les employés de la banque |
|---|
| 191 |
veulent être assurés que, soit toutes les commandes sont effectuées, |
|---|
| 192 |
soit aucune ne l'est. Il n'est pas envisageable que, suite à une erreur |
|---|
| 193 |
du système, Bob reçoive 100 euros qui n'ont pas été débités du compte |
|---|
| 194 |
d'Alice. De la même façon, Alice ne restera pas longtemps une cliente fidèle |
|---|
| 195 |
si elle est débitée du montant sans que celui-ci ne soit crédité sur le compte |
|---|
| 196 |
de Bob. |
|---|
| 197 |
</para> |
|---|
| 198 |
<para> |
|---|
| 199 |
Il est important de garantir que si quelque chose se |
|---|
| 200 |
passe mal, aucune des étapes déjà exécutées n'est prise en compte. Le |
|---|
| 201 |
regroupement des mises à jour au sein d'une <firstterm>transaction</firstterm> |
|---|
| 202 |
apporte cette garantie. |
|---|
| 203 |
Une transaction est dite <firstterm>atomique</firstterm> : |
|---|
| 204 |
du point de vue des autres transactions, elle passe complètement ou pas du tout. |
|---|
| 205 |
</para> |
|---|
| 206 |
|
|---|
| 207 |
<para> |
|---|
| 208 |
Il est également nécessaire de garantir qu'une fois la transaction |
|---|
| 209 |
terminée et validée par la base de données, les transactions sont |
|---|
| 210 |
enregistrées définitivement et ne peuvent être perdues, même si une |
|---|
| 211 |
panne survient peu après. |
|---|
| 212 |
</para> |
|---|
| 213 |
<para> |
|---|
| 214 |
Ainsi, si un retrait d'argent est effectué par Bob, il ne faut |
|---|
| 215 |
absolument pas que le débit de son compte disparaisse avec l'apparition |
|---|
| 216 |
d'une panne juste après son départ de la banque. |
|---|
| 217 |
</para> |
|---|
| 218 |
<para> |
|---|
| 219 |
Une base de données transactionnelle garantit que toutes les mises à jour |
|---|
| 220 |
faites lors d'une transaction sont stockées de manière persistante |
|---|
| 221 |
(c'est-à-dire sur disque) avant que la transaction ne soit déclarée validée. |
|---|
| 222 |
</para> |
|---|
| 223 |
|
|---|
| 224 |
<para> |
|---|
| 225 |
Une autre propriété importante des bases de données transactionnelles est |
|---|
| 226 |
en relation étroite avec la notion de mises à jour atomiques : quand |
|---|
| 227 |
plusieurs transactions sont lancées en parallèle, aucune d'entre elles |
|---|
| 228 |
ne doit être capable de voir les modifications incomplètes effectuées |
|---|
| 229 |
par les autres. |
|---|
| 230 |
</para> |
|---|
| 231 |
<para> |
|---|
| 232 |
Ainsi, si une transaction calcule le total de toutes les branches, |
|---|
| 233 |
inclure le débit de la branche d'Alice sans le crédit de la branche de |
|---|
| 234 |
Bob, ou vice-versa, est une véritable erreur. |
|---|
| 235 |
</para> |
|---|
| 236 |
<para> |
|---|
| 237 |
Les transactions doivent donc être tout-ou-rien, non seulement pour leur |
|---|
| 238 |
effet persistant sur la base de données, mais aussi pour leur visibilité |
|---|
| 239 |
au moment de leur exécution. Les mises à jour faites jusque-là par une |
|---|
| 240 |
transaction ouverte sont invisibles aux autres transactions jusqu'à la fin |
|---|
| 241 |
de celle-là. À ce moment toutes les mises à jours deviennent |
|---|
| 242 |
simultanément visibles. |
|---|
| 243 |
</para> |
|---|
| 244 |
|
|---|
| 245 |
<para> |
|---|
| 246 |
Sous <productname>PostgreSQL</productname>, une transaction est déclarée |
|---|
| 247 |
en entourant les commandes SQL de la transaction par les commandes |
|---|
| 248 |
<command>BEGIN</command> et <command>COMMIT</command>. |
|---|
| 249 |
</para> |
|---|
| 250 |
<para> |
|---|
| 251 |
La transaction bancaire ressemble alors à ceci : |
|---|
| 252 |
|
|---|
| 253 |
<programlisting>BEGIN; |
|---|
| 254 |
UPDATE comptes SET balance = balance - 100.00 |
|---|
| 255 |
WHERE nom = 'Alice'; |
|---|
| 256 |
-- etc etc |
|---|
| 257 |
COMMIT;</programlisting> |
|---|
| 258 |
</para> |
|---|
| 259 |
|
|---|
| 260 |
<para> |
|---|
| 261 |
Si, au cours de la transaction, il est décidé de ne pas valider |
|---|
| 262 |
(peut-être la banque s'aperçoit-elle que la balance d'Alice passe en |
|---|
| 263 |
négatif), la commande <command>ROLLBACK</command> peut être utilisée à |
|---|
| 264 |
la place de <command>COMMIT</command>. Toutes les mises à jour réalisées |
|---|
| 265 |
jusque-là sont alors annulées. |
|---|
| 266 |
</para> |
|---|
| 267 |
|
|---|
| 268 |
<para> |
|---|
| 269 |
En fait, <productname>PostgreSQL</productname> traite chaque instruction SQL comme |
|---|
| 270 |
si elle était exécutée dans une transaction. En l'absence de commande |
|---|
| 271 |
<command>BEGIN</command> explicite, chaque instruction individuelle se trouve |
|---|
| 272 |
implicitement entourée d'un <command>BEGIN</command> et (en cas de succès) d'un |
|---|
| 273 |
<command>COMMIT</command>. |
|---|
| 274 |
</para> |
|---|
| 275 |
<para> |
|---|
| 276 |
Un groupe d'instructions entourées par |
|---|
| 277 |
<command>BEGIN</command> et <command>COMMIT</command> est parfois appelé |
|---|
| 278 |
<firstterm>bloc transactionnel</firstterm>. |
|---|
| 279 |
</para> |
|---|
| 280 |
|
|---|
| 281 |
<note> |
|---|
| 282 |
<para> |
|---|
| 283 |
Quelques bibliothèques clientes lancent les commandes |
|---|
| 284 |
<command>BEGIN</command> et <command>COMMIT</command> automatiquement. |
|---|
| 285 |
L'utilisateur bénéficie alors des effets des blocs transactionnels |
|---|
| 286 |
sans les demander. Ces informations se trouvent en général dans la |
|---|
| 287 |
documentation de l'interface utilisée. |
|---|
| 288 |
</para> |
|---|
| 289 |
</note> |
|---|
| 290 |
|
|---|
| 291 |
<para> |
|---|
| 292 |
Il est possible d'augmenter la granularité du contrôle des instructions |
|---|
| 293 |
au sein d'une transaction en utilisant des |
|---|
| 294 |
<firstterm>points de retournement</firstterm> |
|---|
| 295 |
(<foreignphrase>savepoint</foreignphrase>). Ceux-ci permettent d'annuler des |
|---|
| 296 |
parties de la transaction tout en validant le reste. |
|---|
| 297 |
</para> |
|---|
| 298 |
<para> |
|---|
| 299 |
Après avoir défini un point de retournement à l'aide de |
|---|
| 300 |
<command>SAVEPOINT</command>, les instructions exécutées depuis ce point |
|---|
| 301 |
peuvent, au besoin, être annulées avec <command>ROLLBACK TO</command>. |
|---|
| 302 |
Toutes les modifications de la base de données effectuées par la |
|---|
| 303 |
transaction entre le moment où le point de retournement a été défini et |
|---|
| 304 |
celui où l'annulation est demandée sont annulées mais les modifications |
|---|
| 305 |
antérieures à ce point sont conservées. |
|---|
| 306 |
</para> |
|---|
| 307 |
|
|---|
| 308 |
<para> |
|---|
| 309 |
Le retour à un point de retournement ne l'annule pas. Il reste défini et |
|---|
| 310 |
peut donc être utilisé plusieurs fois. À l'inverse, lorsqu'il n'est plus |
|---|
| 311 |
nécessaire de revenir à un point de sauvegarde pariculier, il peut être |
|---|
| 312 |
relâché, ce qui permet de libérer des ressources systèmes. Il faut |
|---|
| 313 |
savoir toutefois que relâcher un point de retournement, ou y revenir |
|---|
| 314 |
relâche tous les points de sauvegarde qui ont été définis après. |
|---|
| 315 |
</para> |
|---|
| 316 |
|
|---|
| 317 |
<para> |
|---|
| 318 |
Tout ceci survient à l'intérieur du bloc de transaction, et n'est donc pas |
|---|
| 319 |
visible par les autres sessions en cours sur la base de données. Si le |
|---|
| 320 |
bloc est validé, et à ce moment-là seulement, toutes les actions validées |
|---|
| 321 |
deviennent immédiatement visibles par les autres sessions, tandis que |
|---|
| 322 |
les actions annulées ne le seront jamais. |
|---|
| 323 |
</para> |
|---|
| 324 |
|
|---|
| 325 |
<para> |
|---|
| 326 |
Reconsidérant la base de données de la banque, on peut supposer vouloir |
|---|
| 327 |
débiter le compte d'Alice de $100.00, somme à créditer sur le compte de Bob, |
|---|
| 328 |
mais considérer plus tard que c'est le compte de Wally qu'il convient de |
|---|
| 329 |
créditer. À l'aide des points de retournement, cela peut-être réalisé |
|---|
| 330 |
ainsi : |
|---|
| 331 |
|
|---|
| 332 |
<programlisting>BEGIN; |
|---|
| 333 |
UPDATE comptes SET balance = balance - 100.00 |
|---|
| 334 |
WHERE nom = 'Alice'; |
|---|
| 335 |
SAVEPOINT mon_pointdesauvegarde; |
|---|
| 336 |
UPDATE comptes SET balance = balance + 100.00 |
|---|
| 337 |
WHERE nom = 'Bob'; |
|---|
| 338 |
-- oups ... oublions ça et créditons le compte de Wally |
|---|
| 339 |
ROLLBACK TO mon_pointdesauvegarde; |
|---|
| 340 |
UPDATE comptes SET balance = balance + 100.00 |
|---|
| 341 |
WHERE nom = 'Wally'; |
|---|
| 342 |
COMMIT;</programlisting> |
|---|
| 343 |
</para> |
|---|
| 344 |
|
|---|
| 345 |
<para> |
|---|
| 346 |
Cet exemple est bien sûr très simplifié mais de nombreux contrôles sont |
|---|
| 347 |
réalisables au sein d'un bloc de transaction grâce à l'utilisation des points de |
|---|
| 348 |
retournement. Qui plus est, <command>ROLLBACK TO</command> est le seul moyen |
|---|
| 349 |
de regagner le contrôle d'un bloc de transaction placé dans un état |
|---|
| 350 |
d'annulation par le système du fait d'une erreur. C'est plus rapide que |
|---|
| 351 |
de tout annuler pour tout recommencer. |
|---|
| 352 |
</para> |
|---|
| 353 |
</sect1> |
|---|
| 354 |
|
|---|
| 355 |
|
|---|
| 356 |
<sect1 id="tutorial-inheritance"> |
|---|
| 357 |
<title>Héritage</title> |
|---|
| 358 |
|
|---|
| 359 |
<indexterm zone="tutorial-inheritance"> |
|---|
| 360 |
<primary>héritage</primary> |
|---|
| 361 |
<secondary>inheritance</secondary> |
|---|
| 362 |
</indexterm> |
|---|
| 363 |
|
|---|
| 364 |
<para> |
|---|
| 365 |
L'héritage est un concept issu des bases de données orientées objet. |
|---|
| 366 |
Il ouvre de nouvelles possibilités intéressantes en conception de |
|---|
| 367 |
bases de données. |
|---|
| 368 |
</para> |
|---|
| 369 |
|
|---|
| 370 |
<para> |
|---|
| 371 |
Soient deux tables : une table <classname>villes</classname> et une |
|---|
| 372 |
table <classname>capitales</classname>. Les capitales étant également |
|---|
| 373 |
des villes, il est intéressant d'avoir la possibilité d'afficher |
|---|
| 374 |
implicitement les capitales lorsque les villes sont listées. Un |
|---|
| 375 |
utilisateur particulièrement brillant peut écrire ceci |
|---|
| 376 |
|
|---|
| 377 |
<programlisting>CREATE TABLE capitales ( |
|---|
| 378 |
nom text, |
|---|
| 379 |
population real, |
|---|
| 380 |
altitude int, -- (en pied) |
|---|
| 381 |
etat char(2) |
|---|
| 382 |
); |
|---|
| 383 |
|
|---|
| 384 |
CREATE TABLE non_capitales ( |
|---|
| 385 |
nom text, |
|---|
| 386 |
population real, |
|---|
| 387 |
altitude int -- (en pied) |
|---|
| 388 |
); |
|---|
| 389 |
|
|---|
| 390 |
CREATE VIEW villes AS |
|---|
| 391 |
SELECT nom, population, altitude FROM capitales |
|---|
| 392 |
UNION |
|---|
| 393 |
SELECT nom, population, altitude FROM non_capitales;</programlisting> |
|---|
| 394 |
|
|---|
| 395 |
Cela fonctionne bien pour les requêtes, mais la mise à jour d'une même |
|---|
| 396 |
donnée sur plusieurs lignes devient vite un horrible casse-tête. |
|---|
| 397 |
</para> |
|---|
| 398 |
|
|---|
| 399 |
<para> |
|---|
| 400 |
Une meilleure solution peut-être : |
|---|
| 401 |
|
|---|
| 402 |
<programlisting>CREATE TABLE villes ( |
|---|
| 403 |
nom text, |
|---|
| 404 |
population real, |
|---|
| 405 |
altitude int -- (en pied) |
|---|
| 406 |
); |
|---|
| 407 |
|
|---|
| 408 |
CREATE TABLE capitales ( |
|---|
| 409 |
etat char(2) |
|---|
| 410 |
) INHERITS (villes);</programlisting> |
|---|
| 411 |
</para> |
|---|
| 412 |
|
|---|
| 413 |
<para> |
|---|
| 414 |
Dans ce cas, une ligne de <classname>capitales</classname> |
|---|
| 415 |
<firstterm>hérite</firstterm> de toutes les colonnes (<structfield>nom</structfield>, |
|---|
| 416 |
<structfield>population</structfield> et <structfield>altitude</structfield>) de son |
|---|
| 417 |
<firstterm>parent</firstterm>, <classname>villes</classname>. Le type de la |
|---|
| 418 |
colonne <structfield>nom</structfield> est <type>text</type>, un type natif |
|---|
| 419 |
de <productname>PostgreSQL</productname> pour les chaînes de caractères à |
|---|
| 420 |
longueur variable. Les capitales d'état ont une colonne supplémentaire, |
|---|
| 421 |
<structfield>etat</structfield>, qui affiche l'état dont elles sont la |
|---|
| 422 |
capitale. Sous <productname>PostgreSQL</productname>, |
|---|
| 423 |
une table peut hériter de zéro à plusieurs autres tables. |
|---|
| 424 |
</para> |
|---|
| 425 |
|
|---|
| 426 |
<para> |
|---|
| 427 |
La requête qui suit fournit un exemple de récupération des noms de |
|---|
| 428 |
toutes les villes, en incluant les capitales des états, situées à une |
|---|
| 429 |
altitude de plus de 500 pieds : |
|---|
| 430 |
|
|---|
| 431 |
<programlisting>SELECT nom, altitude |
|---|
| 432 |
FROM villes |
|---|
| 433 |
WHERE altitude > 500;</programlisting> |
|---|
| 434 |
|
|---|
| 435 |
ce qui renvoie : |
|---|
| 436 |
|
|---|
| 437 |
<screen> nom | altitude |
|---|
| 438 |
-----------+---------- |
|---|
| 439 |
Las Vegas | 2174 |
|---|
| 440 |
Mariposa | 1953 |
|---|
| 441 |
Madison | 845 |
|---|
| 442 |
(3 rows)</screen> |
|---|
| 443 |
</para> |
|---|
| 444 |
|
|---|
| 445 |
<para> |
|---|
| 446 |
À l'inverse, la requête qui suit récupère toutes les villes qui ne sont pas des |
|---|
| 447 |
capitales et qui sont situées à une altitude d'au moins 500 pieds : |
|---|
| 448 |
|
|---|
| 449 |
<programlisting>SELECT nom, altitude |
|---|
| 450 |
FROM ONLY villes |
|---|
| 451 |
WHERE altitude > 500;</programlisting> |
|---|
| 452 |
|
|---|
| 453 |
<screen> nom | altitude |
|---|
| 454 |
-----------+---------- |
|---|
| 455 |
Las Vegas | 2174 |
|---|
| 456 |
Mariposa | 1953 |
|---|
| 457 |
(2 rows)</screen> |
|---|
| 458 |
</para> |
|---|
| 459 |
|
|---|
| 460 |
<para> |
|---|
| 461 |
Ici, <literal>ONLY</literal> avant <literal>villes</literal> |
|---|
| 462 |
indique que la requête ne doit être exécutée que sur la table |
|---|
| 463 |
<classname>villes</classname>, et non pas sur les tables en dessous de |
|---|
| 464 |
<classname>villes</classname> dans la hiérarchie des héritages. La plupart |
|---|
| 465 |
des commandes déjà évoquées — |
|---|
| 466 |
<command>SELECT</command>, <command>UPDATE</command> et |
|---|
| 467 |
<command>DELETE</command> — supportent cette |
|---|
| 468 |
notation (<literal>ONLY</literal>). |
|---|
| 469 |
</para> |
|---|
| 470 |
|
|---|
| 471 |
<note> |
|---|
| 472 |
<para> |
|---|
| 473 |
Bien que l'héritage soit fréquemment utile, il n'a pas été intégré avec |
|---|
| 474 |
les contraintes d'unicité et les clés étrangères, ce qui limite son utilité. |
|---|
| 475 |
Voir la <xref linkend="ddl-inherit"/> pour plus de détails. |
|---|
| 476 |
</para> |
|---|
| 477 |
</note> |
|---|
| 478 |
</sect1> |
|---|
| 479 |
|
|---|
| 480 |
|
|---|
| 481 |
<sect1 id="tutorial-conclusion"> |
|---|
| 482 |
<title>Conclusion</title> |
|---|
| 483 |
|
|---|
| 484 |
<para> |
|---|
| 485 |
<productname>PostgreSQL</productname> dispose d'autres fonctionnalités |
|---|
| 486 |
non décrites dans ce tutoriel d'introduction orienté vers |
|---|
| 487 |
les nouveaux utilisateurs de <acronym>SQL</acronym>. Ces fonctionnalités |
|---|
| 488 |
sont discutées plus en détails dans le reste de ce livre. |
|---|
| 489 |
</para> |
|---|
| 490 |
|
|---|
| 491 |
<para> |
|---|
| 492 |
Si une introduction plus approfondie est nécessaire, le lecteur peut |
|---|
| 493 |
visiter le <ulink url="http://www.postgresql.org">site web</ulink> |
|---|
| 494 |
de PostgreSQL qui fournit des liens vers d'autres ressources. |
|---|
| 495 |
</para> |
|---|
| 496 |
</sect1> |
|---|
| 497 |
</chapter> |
|---|
| 498 |
|
|---|