| 1 |
<!-- |
|---|
| 2 |
$Header: /var/lib/cvs/pgsql-fr/sgml/advanced.sgml,v 1.8.2.2 2005/07/15 06:33:35 guillaume Exp $ |
|---|
| 3 |
--> |
|---|
| 4 |
|
|---|
| 5 |
<chapter id="tutorial-advanced"> |
|---|
| 6 |
<title>Fonctionnalités avancées</title> |
|---|
| 7 |
|
|---|
| 8 |
<sect1 id="tutorial-advanced-intro"> |
|---|
| 9 |
<title>Introduction</title> |
|---|
| 10 |
|
|---|
| 11 |
<para> |
|---|
| 12 |
Dans le précédent chapitre, nous avons couvert les bases de l'utilisation |
|---|
| 13 |
de <acronym>SQL</acronym> pour stocker et accéder à vos données avec |
|---|
| 14 |
<productname>PostgreSQL</productname>. Nous allons maintenant discuter de |
|---|
| 15 |
quelques fonctionnalités avancées de <acronym>SQL</acronym> |
|---|
| 16 |
simplifiant la gestion et empêchant la perte ou la corruption de vos |
|---|
| 17 |
données. Enfin, nous regarderons quelques extensions de |
|---|
| 18 |
<productname>PostgreSQL</productname>. |
|---|
| 19 |
</para> |
|---|
| 20 |
|
|---|
| 21 |
<para> |
|---|
| 22 |
Ce chapitre se référera occasionnellement aux exemples disponibles dans le |
|---|
| 23 |
<xref linkend="tutorial-sql"> pour les modifier ou les améliorer, donc il |
|---|
| 24 |
serait avantageux d'avoir lu ce chapitre. Quelques exemples de ce |
|---|
| 25 |
chapitre sont aussi disponibles dans <filename>advanced.sql</filename> |
|---|
| 26 |
placé dans le répertoire du tutoriel. Ce fichier contient aussi quelques |
|---|
| 27 |
données à charger pour l'exemple, ce qui ne sera pas répété ici. |
|---|
| 28 |
(Référez-vous à la <xref linkend="tutorial-sql-intro"> pour savoir comment |
|---|
| 29 |
utiliser ce fichier.) |
|---|
| 30 |
</para> |
|---|
| 31 |
</sect1> |
|---|
| 32 |
|
|---|
| 33 |
|
|---|
| 34 |
<sect1 id="tutorial-views"> |
|---|
| 35 |
<title>Vues</title> |
|---|
| 36 |
|
|---|
| 37 |
<indexterm zone="tutorial-views"> |
|---|
| 38 |
<primary>vue</primary> |
|---|
| 39 |
<secondary>view</secondary> |
|---|
| 40 |
</indexterm> |
|---|
| 41 |
|
|---|
| 42 |
<para> |
|---|
| 43 |
Référez-vous aux requêtes de la <xref linkend="tutorial-join">. |
|---|
| 44 |
Supposons que la liste des enregistrements du temps et des villes soit d'un |
|---|
| 45 |
intérêt particulier pour votre application mais que vous ne voulez pas |
|---|
| 46 |
saisir la requête à chaque fois que vous en avez besoin. Vous pouvez créer |
|---|
| 47 |
une <firstterm>vue</firstterm> avec la requête, ce qui donne un nom à la |
|---|
| 48 |
requête à laquelle vous pouvez vous référer comme dans le cas d'une table |
|---|
| 49 |
ordinaire. |
|---|
| 50 |
|
|---|
| 51 |
<programlisting> |
|---|
| 52 |
CREATE VIEW mavue AS |
|---|
| 53 |
SELECT ville, temp_basse, temp_haute, prcp, date, emplacement |
|---|
| 54 |
FROM temps, villes |
|---|
| 55 |
WHERE ville = nom; |
|---|
| 56 |
|
|---|
| 57 |
SELECT * FROM mavue; |
|---|
| 58 |
</programlisting> |
|---|
| 59 |
</para> |
|---|
| 60 |
|
|---|
| 61 |
<para> |
|---|
| 62 |
Avoir une utilisation libérale des vues est un aspect clé d'une bonne |
|---|
| 63 |
conception des base de données avec SQL. Les vues vous permettent |
|---|
| 64 |
d'encapsuler les détails de la structure de vos tables, qui pourraient |
|---|
| 65 |
changer lors de l'évolution de votre application, tout en restant |
|---|
| 66 |
consistant au niveau de l'interface. |
|---|
| 67 |
</para> |
|---|
| 68 |
|
|---|
| 69 |
<para> |
|---|
| 70 |
Les vues peuvent être utilisées pratiquement partout où une vraie table est |
|---|
| 71 |
utilisable. Construire des vues basées sur d'autres vues n'est pas |
|---|
| 72 |
inhabituel. |
|---|
| 73 |
</para> |
|---|
| 74 |
</sect1> |
|---|
| 75 |
|
|---|
| 76 |
|
|---|
| 77 |
<sect1 id="tutorial-fk"> |
|---|
| 78 |
<title>Clés secondaires</title> |
|---|
| 79 |
|
|---|
| 80 |
<indexterm zone="tutorial-fk"> |
|---|
| 81 |
<primary>clé secondaire</primary> |
|---|
| 82 |
<secondary>foreign key</secondary> |
|---|
| 83 |
</indexterm> |
|---|
| 84 |
|
|---|
| 85 |
<indexterm zone="tutorial-fk"> |
|---|
| 86 |
<primary>intégrité référencielle</primary> |
|---|
| 87 |
<secondary>referential integrity</secondary> |
|---|
| 88 |
</indexterm> |
|---|
| 89 |
|
|---|
| 90 |
<para> |
|---|
| 91 |
Souvenez-vous des tables <classname>temps</classname> et |
|---|
| 92 |
<classname>villes</classname> du <xref linkend="tutorial-sql">. |
|---|
| 93 |
Considérez le problème suivant : vous voulez vous assurer que personne |
|---|
| 94 |
n'insère de lignes dans la table <classname>temps</classname> qui ne |
|---|
| 95 |
correspondraient pas à une entrée dans la table |
|---|
| 96 |
<classname>villes</classname>. Ceci maintient l'<firstterm>intégrité |
|---|
| 97 |
référencielle</firstterm> de vos données. Dans les systèmes de bases de |
|---|
| 98 |
données simples, ceci serait implémenté (si possible) en vérifiant en |
|---|
| 99 |
premier lieu que la table <classname>ville</classname> dispose bien d'un |
|---|
| 100 |
enregistrement correspondant, puis en insérant ou en empêchant l'insertion |
|---|
| 101 |
du nouvel enregistrement dans <classname>temps</classname>. Cette approche |
|---|
| 102 |
présente un certain nombre de problèmes et n'est pas très simple, donc |
|---|
| 103 |
<productname>PostgreSQL</productname> peut s'en charger pour vous. |
|---|
| 104 |
</para> |
|---|
| 105 |
|
|---|
| 106 |
<para> |
|---|
| 107 |
La nouvelle déclaration des tables ressemblerait à ceci : |
|---|
| 108 |
|
|---|
| 109 |
<programlisting> |
|---|
| 110 |
CREATE TABLE villes ( |
|---|
| 111 |
ville varchar(80) primary key, |
|---|
| 112 |
emplacement point |
|---|
| 113 |
); |
|---|
| 114 |
|
|---|
| 115 |
CREATE TABLE temps ( |
|---|
| 116 |
ville varchar(80) references villes, |
|---|
| 117 |
temp_haute int, |
|---|
| 118 |
temp_basse int, |
|---|
| 119 |
prcp real, |
|---|
| 120 |
date date |
|---|
| 121 |
); |
|---|
| 122 |
</programlisting> |
|---|
| 123 |
|
|---|
| 124 |
Maintenant, essayons d'insérer un enregistrement non valide : |
|---|
| 125 |
|
|---|
| 126 |
<programlisting> |
|---|
| 127 |
INSERT INTO temps VALUES ('Berkeley', 45, 53, 0.0, '1994-11-28'); |
|---|
| 128 |
</programlisting> |
|---|
| 129 |
|
|---|
| 130 |
<screen> |
|---|
| 131 |
ERROR: insert or update on table "temps" violates foreign key constraint "$1" |
|---|
| 132 |
DETAIL: Key (ville)=(Berkeley) is not present in table "villes". |
|---|
| 133 |
</screen> |
|---|
| 134 |
</para> |
|---|
| 135 |
|
|---|
| 136 |
<para> |
|---|
| 137 |
Le comportement des clés secondaires peut être précisé très finement pour |
|---|
| 138 |
votre application. Nous n'irons pas plus loin que cet exemple simple dans |
|---|
| 139 |
ce tutoriel mais référez-vous simplement au <xref linkend="ddl"> pour plus |
|---|
| 140 |
d'informations. Utiliser correctement les clés secondaires améliore la |
|---|
| 141 |
qualité de vos applications de bases de données, donc vous êtes fortement |
|---|
| 142 |
encouragé à les connaître. |
|---|
| 143 |
</para> |
|---|
| 144 |
</sect1> |
|---|
| 145 |
|
|---|
| 146 |
|
|---|
| 147 |
<sect1 id="tutorial-transactions"> |
|---|
| 148 |
<title>Transactions</title> |
|---|
| 149 |
|
|---|
| 150 |
<indexterm zone="tutorial-transactions"> |
|---|
| 151 |
<primary>transaction</primary> |
|---|
| 152 |
</indexterm> |
|---|
| 153 |
|
|---|
| 154 |
<para> |
|---|
| 155 |
Les <firstterm>transactions</> sont un concept fondamental de tous les |
|---|
| 156 |
systèmes de bases de données. Le point essentiel d'une transaction est |
|---|
| 157 |
qu'il assemble plusieurs étapes en une seule, une opération tout-ou-rien. |
|---|
| 158 |
Les états intermédiaires entre les étapes ne sont pas visibles pour les |
|---|
| 159 |
autres transactions concurrentes, et si un échec survient empêchant la fin |
|---|
| 160 |
réussie de la transaction, alors aucune des étapes n'affecte la base de |
|---|
| 161 |
données. |
|---|
| 162 |
</para> |
|---|
| 163 |
|
|---|
| 164 |
<para> |
|---|
| 165 |
Par exemple, considérez la base de données d'une banque qui contiendrait la |
|---|
| 166 |
balance pour différents comptes clients, ainsi que les balances du total du |
|---|
| 167 |
dépôt par branches. Supposez que nous voulons enregistrer un virement de |
|---|
| 168 |
100 euros du compte d'Alice vers celui de Bob. En simplifiant énormément, |
|---|
| 169 |
les commandes SQL pour ceci ressembleraient à ça |
|---|
| 170 |
|
|---|
| 171 |
<programlisting> |
|---|
| 172 |
UPDATE comptes SET balance = balance - 100.00 |
|---|
| 173 |
WHERE nom = 'Alice'; |
|---|
| 174 |
UPDATE branches SET balance = balance - 100.00 |
|---|
| 175 |
WHERE nom = (SELECT nom_branche FROM comptes WHERE nom = 'Alice'); |
|---|
| 176 |
UPDATE comptes SET balance = balance + 100.00 |
|---|
| 177 |
WHERE nom = 'Bob'; |
|---|
| 178 |
UPDATE branches SET balance = balance + 100.00 |
|---|
| 179 |
WHERE nom = (SELECT nom_branche FROM comptes WHERE nom = 'Bob'); |
|---|
| 180 |
</programlisting> |
|---|
| 181 |
</para> |
|---|
| 182 |
|
|---|
| 183 |
<para> |
|---|
| 184 |
Les détails de ces commandes ne sont pas importants ici ; le point |
|---|
| 185 |
important est que cela nécessite plusieurs mises à jour séparées pour |
|---|
| 186 |
accomplir cette opération assez simple. Les officiels de la banque |
|---|
| 187 |
voudront être assurés que soit toutes les commandes sont effectuées |
|---|
| 188 |
soit aucune ne l'ait. Il ne serait pas acceptable que, suite à une erreur |
|---|
| 189 |
du système, Bob reçoive 100 euros qui n'ont pas été débités du compte |
|---|
| 190 |
d'Alice. De la même façon, Alice ne restera pas longtemps une cliente si |
|---|
| 191 |
elle est débitée du montant sans que celui-ci ne soit crédité sur le compte |
|---|
| 192 |
de Bob. Nous avons besoin d'une garantie comme quoi si quelque chose se |
|---|
| 193 |
passe mal, aucune des étapes déjà exécutées ne prendra effet. Grouper les |
|---|
| 194 |
mises à jour en une <firstterm>transaction</> nous donne cette garantie. |
|---|
| 195 |
Une transaction est dite <firstterm>atomique</> : du point de vue des autres |
|---|
| 196 |
transactions, cela se passe complètement ou pas du tout. |
|---|
| 197 |
</para> |
|---|
| 198 |
|
|---|
| 199 |
<para> |
|---|
| 200 |
Nous voulons aussi la garantie qu'une fois une transaction terminée et |
|---|
| 201 |
validée par le système de base de données, les modifications seront |
|---|
| 202 |
enregistrées de façon permanente et ne seront pas perdues même si un arrêt |
|---|
| 203 |
brutal arrive peu après. Par exemple, si nous enregistrons un retrait |
|---|
| 204 |
d'argent par Bob, nous ne voulons surtout pas que le débit de son compte |
|---|
| 205 |
disparaisse lors d'un crash à sa sortie de la banque. Une base de données |
|---|
| 206 |
transactionnelle garantie que toutes les mises à jour faites lors d'une |
|---|
| 207 |
transaction sont enregistrées dans un stockage permanent (c'est-à-dire sur |
|---|
| 208 |
disque) avant que la transaction ne soit validée. |
|---|
| 209 |
</para> |
|---|
| 210 |
|
|---|
| 211 |
<para> |
|---|
| 212 |
Une autre propriété importante des bases de données transactionnelles est |
|---|
| 213 |
en relation étroite avec la notion de mises à jour atomiques : quand |
|---|
| 214 |
de multiples transactions sont lancées en parallèle, chacune d'entre elles |
|---|
| 215 |
ne doit pas être capable de voir les modifications incomplètes faites |
|---|
| 216 |
par les autres. Par exemple, si une transaction est occupée en faisant le |
|---|
| 217 |
total de toutes les branches, il ne serait pas bon d'inclure le débit de la |
|---|
| 218 |
branche d'Alice mais sans le crédit de la branche de Bob, ou vice-versa. |
|---|
| 219 |
Donc, les transactions doivent être tout-ou-rien non seulement pour leur |
|---|
| 220 |
effet permanent sur la base de données, mais aussi pour leur visibilité |
|---|
| 221 |
au moment de leur exécution. Les mises à jour faites ainsi par une |
|---|
| 222 |
transaction ouverte sont invisibles aux autres transactions jusqu'à la fin |
|---|
| 223 |
de celle-ci, moment qui rendra visible toutes les mises à jours |
|---|
| 224 |
simultanément. |
|---|
| 225 |
</para> |
|---|
| 226 |
|
|---|
| 227 |
<para> |
|---|
| 228 |
Avec <productname>PostgreSQL</>, une transaction est réalisée en entourant |
|---|
| 229 |
les commandes SQL de la transaction avec les commandes <command>BEGIN</> |
|---|
| 230 |
et <command>COMMIT</>. Donc, notre transaction pour la banque ressemblera à |
|---|
| 231 |
ceci |
|---|
| 232 |
|
|---|
| 233 |
<programlisting> |
|---|
| 234 |
BEGIN; |
|---|
| 235 |
UPDATE comptes SET balance = balance - 100.00 |
|---|
| 236 |
WHERE nom = 'Alice'; |
|---|
| 237 |
-- etc etc |
|---|
| 238 |
COMMIT; |
|---|
| 239 |
</programlisting> |
|---|
| 240 |
</para> |
|---|
| 241 |
|
|---|
| 242 |
<para> |
|---|
| 243 |
Si, au cours de la transaction, nous décidons que nous ne voulons pas |
|---|
| 244 |
valider (peut-être nous sommes-nous aperçu que la balance d'Alice devenait |
|---|
| 245 |
négative), nous pouvons envoyer la commande <command>ROLLBACK</> au lieu de |
|---|
| 246 |
<command>COMMIT</>, et toutes nos mises à jour jusqu'à maintenant seront |
|---|
| 247 |
annulées. |
|---|
| 248 |
</para> |
|---|
| 249 |
|
|---|
| 250 |
<para> |
|---|
| 251 |
En fait, <productname>PostgreSQL</> traite chaque instruction SQL comme |
|---|
| 252 |
étant exécutée dans une transaction. Si vous ne lancez pas une commande |
|---|
| 253 |
<command>BEGIN</>, alors chaque instruction individuelle se trouve |
|---|
| 254 |
enveloppée avec un <command>BEGIN</> et (en cas de succès) un |
|---|
| 255 |
<command>COMMIT</> implicites. Un groupe d'instructions entouré par un |
|---|
| 256 |
<command>BEGIN</> et un <command>COMMIT</> est quelque fois appelé un |
|---|
| 257 |
<firstterm>bloc transactionnel</>. |
|---|
| 258 |
</para> |
|---|
| 259 |
|
|---|
| 260 |
<note> |
|---|
| 261 |
<para> |
|---|
| 262 |
Quelques bibliothèques clients lancent les commandes <command>BEGIN</> et |
|---|
| 263 |
<command>COMMIT</> automatiquement, de façon à ce que vous bénéficiiez des |
|---|
| 264 |
effets des blocs transactionnels sans les demander. Vérifiez la |
|---|
| 265 |
documentation de l'interface que vous utilisez. |
|---|
| 266 |
</para> |
|---|
| 267 |
</note> |
|---|
| 268 |
</sect1> |
|---|
| 269 |
|
|---|
| 270 |
|
|---|
| 271 |
<sect1 id="tutorial-inheritance"> |
|---|
| 272 |
<title>Héritage</title> |
|---|
| 273 |
|
|---|
| 274 |
<indexterm zone="tutorial-inheritance"> |
|---|
| 275 |
<primary>héritage</primary> |
|---|
| 276 |
<secondary>inheritance</secondary> |
|---|
| 277 |
</indexterm> |
|---|
| 278 |
|
|---|
| 279 |
<para> |
|---|
| 280 |
L'héritage est un concept provenant des bases de données orientées objet. |
|---|
| 281 |
Il ouvre de nouvelles possibilités intéressantes dans la conception de |
|---|
| 282 |
bases de données. |
|---|
| 283 |
</para> |
|---|
| 284 |
|
|---|
| 285 |
<para> |
|---|
| 286 |
Créons deux tables : une table <classname>villes</classname> et une |
|---|
| 287 |
table <classname>capitales</classname>. Naturellement, les capitales sont |
|---|
| 288 |
aussi des villes, donc vous voulez un moyen pour afficher implicitement les |
|---|
| 289 |
capitales lorsque vous listez les villes. Si vous êtes réellement |
|---|
| 290 |
intelligent, vous pourriez inventer ceci : |
|---|
| 291 |
|
|---|
| 292 |
<programlisting> |
|---|
| 293 |
CREATE TABLE capitales ( |
|---|
| 294 |
nom text, |
|---|
| 295 |
population real, |
|---|
| 296 |
altitude int, -- (en pied) |
|---|
| 297 |
etat char(2) |
|---|
| 298 |
); |
|---|
| 299 |
|
|---|
| 300 |
CREATE TABLE non_capitales ( |
|---|
| 301 |
nom text, |
|---|
| 302 |
population real, |
|---|
| 303 |
altitude int -- (en pied) |
|---|
| 304 |
); |
|---|
| 305 |
|
|---|
| 306 |
CREATE VIEW villes AS |
|---|
| 307 |
SELECT nom, population, altitude FROM capitales |
|---|
| 308 |
UNION |
|---|
| 309 |
SELECT nom, population, altitude FROM non_capitales; |
|---|
| 310 |
</programlisting> |
|---|
| 311 |
|
|---|
| 312 |
Ceci fonctionne bien pour les requêtes, mais c'est horrible lorsque vous |
|---|
| 313 |
avez besoin de mettre à jour plusieurs lignes par exemple. |
|---|
| 314 |
</para> |
|---|
| 315 |
|
|---|
| 316 |
<para> |
|---|
| 317 |
Voici une meilleure solution : |
|---|
| 318 |
|
|---|
| 319 |
<programlisting> |
|---|
| 320 |
CREATE TABLE villes ( |
|---|
| 321 |
nom text, |
|---|
| 322 |
population real, |
|---|
| 323 |
altitude int -- (en pied) |
|---|
| 324 |
); |
|---|
| 325 |
|
|---|
| 326 |
CREATE TABLE capitales ( |
|---|
| 327 |
etat char(2) |
|---|
| 328 |
) INHERITS (villes); |
|---|
| 329 |
</programlisting> |
|---|
| 330 |
</para> |
|---|
| 331 |
|
|---|
| 332 |
<para> |
|---|
| 333 |
Dans ce cas, une ligne de <classname>capitales</classname> |
|---|
| 334 |
<firstterm>hérite</firstterm> de toutes les colonnes (<structfield>nom</>, |
|---|
| 335 |
<structfield>population</> et <structfield>altitude</>) de son |
|---|
| 336 |
<firstterm>parent</firstterm>, <classname>villes</classname>. Le type de la |
|---|
| 337 |
colonne <structfield>nom</structfield> est <type>text</type>, un type natif |
|---|
| 338 |
de <productname>PostgreSQL</productname> pour les chaînes de caractères à |
|---|
| 339 |
longueur variable. Les capitales d'état ont une colonne supplémentaire, |
|---|
| 340 |
etat, qui affiche leur état. Dans <productname>PostgreSQL</productname>, |
|---|
| 341 |
une table peut hériter d'aucune ou de plusieurs autres tables. |
|---|
| 342 |
</para> |
|---|
| 343 |
|
|---|
| 344 |
<para> |
|---|
| 345 |
Par exemple, la requête suivante trouve les noms de toutes les villes, en |
|---|
| 346 |
incluant les capitales des états, situées à une altitude de plus de 500 |
|---|
| 347 |
pieds : |
|---|
| 348 |
|
|---|
| 349 |
<programlisting> |
|---|
| 350 |
SELECT nom, altitude |
|---|
| 351 |
FROM villes |
|---|
| 352 |
WHERE altitude > 500; |
|---|
| 353 |
</programlisting> |
|---|
| 354 |
|
|---|
| 355 |
ce qui renvoie : |
|---|
| 356 |
|
|---|
| 357 |
<screen> |
|---|
| 358 |
nom | altitude |
|---|
| 359 |
-----------+---------- |
|---|
| 360 |
Las Vegas | 2174 |
|---|
| 361 |
Mariposa | 1953 |
|---|
| 362 |
Madison | 845 |
|---|
| 363 |
(3 rows) |
|---|
| 364 |
</screen> |
|---|
| 365 |
</para> |
|---|
| 366 |
|
|---|
| 367 |
<para> |
|---|
| 368 |
Autrement, la requête suivante trouve toutes les villes qui ne sont pas des |
|---|
| 369 |
capitales et qui sont situées à une altitude d'au moins 500 pieds : |
|---|
| 370 |
|
|---|
| 371 |
<programlisting> |
|---|
| 372 |
SELECT nom, altitude |
|---|
| 373 |
FROM ONLY villes |
|---|
| 374 |
WHERE altitude > 500; |
|---|
| 375 |
</programlisting> |
|---|
| 376 |
|
|---|
| 377 |
<screen> |
|---|
| 378 |
nom | altitude |
|---|
| 379 |
-----------+---------- |
|---|
| 380 |
Las Vegas | 2174 |
|---|
| 381 |
Mariposa | 1953 |
|---|
| 382 |
(2 rows) |
|---|
| 383 |
</screen> |
|---|
| 384 |
</para> |
|---|
| 385 |
|
|---|
| 386 |
<para> |
|---|
| 387 |
Ici, <literal>ONLY</literal> avant <literal>villes</literal> |
|---|
| 388 |
indique que la requête ne doit être lancée que sur la table |
|---|
| 389 |
<classname>villes</classname>, et non pas sur les tables sous |
|---|
| 390 |
<classname>villes</classname> suivant la hiérarchie des héritages. Beaucoup |
|---|
| 391 |
des commandes dont nous avons déjà discutées -- <command>SELECT</command>, |
|---|
| 392 |
<command>UPDATE</command> et <command>DELETE</command> -- supportent cette |
|---|
| 393 |
notation (<literal>ONLY</literal>). |
|---|
| 394 |
</para> |
|---|
| 395 |
</sect1> |
|---|
| 396 |
|
|---|
| 397 |
|
|---|
| 398 |
<sect1 id="tutorial-conclusion"> |
|---|
| 399 |
<title>Conclusion</title> |
|---|
| 400 |
|
|---|
| 401 |
<para> |
|---|
| 402 |
<productname>PostgreSQL</productname> a bien plus de fonctionnalités que |
|---|
| 403 |
celles aperçues lors de ce tutoriel d'introduction, qui a été orienté vers |
|---|
| 404 |
les nouveaux utilisateurs de <acronym>SQL</acronym>. Ces fonctionnalités |
|---|
| 405 |
sont discutées avec plus de détails dans le reste de ce livre. |
|---|
| 406 |
</para> |
|---|
| 407 |
|
|---|
| 408 |
<para> |
|---|
| 409 |
Si vous sentez que vous avez besoin d'une introduction plus approfondie, |
|---|
| 410 |
merci de visiter le <ulink url="http://www.postgresql.org">site web |
|---|
| 411 |
PostgreSQL</ulink> pour des liens vers d'autres ressources. |
|---|
| 412 |
</para> |
|---|
| 413 |
</sect1> |
|---|
| 414 |
</chapter> |
|---|
| 415 |
|
|---|
| 416 |
<!-- Keep this comment at the end of the file |
|---|
| 417 |
Local variables: |
|---|
| 418 |
mode:sgml |
|---|
| 419 |
sgml-omittag:nil |
|---|
| 420 |
sgml-shorttag:t |
|---|
| 421 |
sgml-minimize-attributes:nil |
|---|
| 422 |
sgml-always-quote-attributes:t |
|---|
| 423 |
sgml-indent-step:1 |
|---|
| 424 |
sgml-indent-data:t |
|---|
| 425 |
sgml-parent-document:nil |
|---|
| 426 |
sgml-default-dtd-file:"./reference.ced" |
|---|
| 427 |
sgml-exposed-tags:nil |
|---|
| 428 |
sgml-local-catalogs:("/usr/lib/sgml/catalog") |
|---|
| 429 |
sgml-local-ecat-files:nil |
|---|
| 430 |
End: |
|---|
| 431 |
--> |
|---|