| 1 | <?xml version="1.0" encoding="ISO-8859-15"?> |
|---|
| 2 | <!-- Dernière modification |
|---|
| 3 | le $Date$ |
|---|
| 4 | par $Author$ |
|---|
| 5 | révision $Revision$ --> |
|---|
| 6 | |
|---|
| 7 | <chapter id="queries"> |
|---|
| 8 | <title>Requêtes</title> |
|---|
| 9 | |
|---|
| 10 | <indexterm zone="queries"> |
|---|
| 11 | <primary>requête</primary> |
|---|
| 12 | </indexterm> |
|---|
| 13 | |
|---|
| 14 | <indexterm zone="queries"> |
|---|
| 15 | <primary>SELECT</primary> |
|---|
| 16 | </indexterm> |
|---|
| 17 | |
|---|
| 18 | <para> |
|---|
| 19 | Les précédents chapitres ont expliqué comme créer des tables, comment |
|---|
| 20 | les remplir avec des données et comment manipuler ces données. |
|---|
| 21 | Maintenant, nous discutons enfin de la façon de récupérer ces données |
|---|
| 22 | depuis la base de données. |
|---|
| 23 | </para> |
|---|
| 24 | |
|---|
| 25 | |
|---|
| 26 | <sect1 id="queries-overview"> |
|---|
| 27 | <title>Aperçu</title> |
|---|
| 28 | |
|---|
| 29 | <para> |
|---|
| 30 | Le processus et la commande de récupération des données sont appelés une |
|---|
| 31 | <firstterm>requête</firstterm>. En SQL, la commande <xref linkend="sql-select" |
|---|
| 32 | endterm="sql-select-title"/> est utilisée pour spécifier des requêtes. La |
|---|
| 33 | syntaxe générale de la commande <command>SELECT</command> est |
|---|
| 34 | <synopsis> |
|---|
| 35 | <optional>WITH <replaceable>with_requêtes</replaceable></optional> SELECT <replaceable>liste_select</replaceable> FROM <replaceable>expression_table</replaceable> <optional><replaceable>specification_tri</replaceable></optional> |
|---|
| 36 | </synopsis> |
|---|
| 37 | Les sections suivantes décrivent le détail de la liste de sélection, |
|---|
| 38 | l'expression des tables et la spécification du tri. Les requêtes |
|---|
| 39 | <literal>WITH</literal> sont traitées en dernier car il s'agit d'une |
|---|
| 40 | fonctionnalité avancée. |
|---|
| 41 | </para> |
|---|
| 42 | |
|---|
| 43 | <para> |
|---|
| 44 | Un type de requête simple est de la forme : |
|---|
| 45 | <programlisting>SELECT * FROM table1;</programlisting> |
|---|
| 46 | En supposant qu'il existe une table appelée <literal>table1</literal>, cette |
|---|
| 47 | commande récupérera toutes les lignes et toutes les colonnes de |
|---|
| 48 | <literal>table1</literal>. La méthode de récupération dépend de l'application |
|---|
| 49 | cliente. Par exemple, le programme <application>psql</application> affichera |
|---|
| 50 | une table, façon art ASCII, alors que les bibliothèques du client offriront |
|---|
| 51 | des fonctions d'extraction de valeurs individuelles à partir du résultat de |
|---|
| 52 | la requête. <literal>*</literal> comme liste de sélection signifie que toutes |
|---|
| 53 | les colonnes de l'expression de table seront récupérées. Une liste de sélection |
|---|
| 54 | peut aussi être un sous-ensemble des colonnes disponibles ou effectuer |
|---|
| 55 | un calcul en utilisant les colonnes. Par exemple, si <literal>table1</literal> |
|---|
| 56 | dispose des colonnes nommées <literal>a</literal>, <literal>b</literal> et <literal>c</literal> (et |
|---|
| 57 | peut-être d'autres), vous pouvez lancer la requête suivante : |
|---|
| 58 | <programlisting>SELECT a, b + c FROM table1;</programlisting> |
|---|
| 59 | (en supposant que <literal>b</literal> et <literal>c</literal> soient de type numérique). |
|---|
| 60 | Voir la <xref linkend="queries-select-lists"/> pour plus de détails. |
|---|
| 61 | </para> |
|---|
| 62 | |
|---|
| 63 | <para> |
|---|
| 64 | <literal>FROM table1</literal> est un type très simple d'expression de |
|---|
| 65 | tables : il lit une seule table. En général, les expressions de tables |
|---|
| 66 | sont des constructions complexes de tables de base, de jointures et de |
|---|
| 67 | sous-requêtes. Mais vous pouvez aussi entièrement omettre l'expression de table |
|---|
| 68 | et utiliser la commande <command>SELECT</command> comme une calculatrice : |
|---|
| 69 | <programlisting>SELECT 3 * 4;</programlisting> |
|---|
| 70 | Ceci est plus utile si les expressions de la liste de sélection renvoient des |
|---|
| 71 | résultats variants. Par exemple, vous pouvez appeler une fonction de cette |
|---|
| 72 | façon : |
|---|
| 73 | <programlisting>SELECT random();</programlisting> |
|---|
| 74 | </para> |
|---|
| 75 | </sect1> |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | <sect1 id="queries-table-expressions"> |
|---|
| 79 | <title>Expressions de table</title> |
|---|
| 80 | |
|---|
| 81 | <indexterm zone="queries-table-expressions"> |
|---|
| 82 | <primary>expression de table</primary> |
|---|
| 83 | </indexterm> |
|---|
| 84 | |
|---|
| 85 | <para> |
|---|
| 86 | Une <firstterm>expression de table</firstterm> calcule une table. |
|---|
| 87 | L'expression de table contient une clause <literal>FROM</literal> qui peut être |
|---|
| 88 | suivie des clauses <literal>WHERE</literal>, <literal>GROUP BY</literal> et |
|---|
| 89 | <literal>HAVING</literal>. Les expressions triviales de table font simplement |
|---|
| 90 | référence à une table sur le disque, une table de base, mais des expressions |
|---|
| 91 | plus complexes peuvent être utilisées pour modifier ou combiner des tables |
|---|
| 92 | de base de différentes façons. |
|---|
| 93 | </para> |
|---|
| 94 | |
|---|
| 95 | <para> |
|---|
| 96 | Les clauses optionnelles <literal>WHERE</literal>, <literal>GROUP BY</literal> et |
|---|
| 97 | <literal>HAVING</literal> dans l'expression de table spécifient un tube de |
|---|
| 98 | transformations successives réalisées sur la table dérivée de la |
|---|
| 99 | clause <literal>FROM</literal>. Toutes ces transformations produisent une table |
|---|
| 100 | virtuelle fournissant les lignes à passer à la liste de sélection qui |
|---|
| 101 | choisira les lignes à afficher de la requête. |
|---|
| 102 | </para> |
|---|
| 103 | |
|---|
| 104 | <sect2 id="queries-from"> |
|---|
| 105 | <title>Clause <literal>FROM</literal></title> |
|---|
| 106 | |
|---|
| 107 | <para> |
|---|
| 108 | La <xref linkend="sql-from" endterm="sql-from-title"/> dérive une |
|---|
| 109 | table à partir d'une ou plusieurs tables données dans une liste de |
|---|
| 110 | référence dont les tables sont séparées par des virgules. |
|---|
| 111 | <synopsis>FROM <replaceable>reference_table</replaceable> <optional>, <replaceable>reference_table</replaceable> <optional>, ...</optional></optional></synopsis> |
|---|
| 112 | |
|---|
| 113 | Une référence de table pourrait être un nom de table (avec en option |
|---|
| 114 | le nom du schéma) ou une table dérivée comme une sous-requête, une table |
|---|
| 115 | jointe ou une combinaison complexe de celles-ci. Si plus d'une référence de |
|---|
| 116 | tables est listée dans la clause <literal>FROM</literal>, elle sont jointes pour |
|---|
| 117 | former une table virtuelle intermédiaire qui pourrait être le sujet des |
|---|
| 118 | transformations des clauses <literal>WHERE</literal>, <literal>GROUP BY</literal> |
|---|
| 119 | et <literal>HAVING</literal>, et est finalement le résultat des expressions de |
|---|
| 120 | table. |
|---|
| 121 | </para> |
|---|
| 122 | |
|---|
| 123 | <indexterm> |
|---|
| 124 | <primary>ONLY</primary> |
|---|
| 125 | </indexterm> |
|---|
| 126 | |
|---|
| 127 | <para> |
|---|
| 128 | Lorsqu'une référence de table nomme une table qui est la table parent d'une |
|---|
| 129 | table suivant la hiérarchie de l'héritage, la référence de table produit les |
|---|
| 130 | lignes non seulement de la table mais aussi des descendants de cette table |
|---|
| 131 | sauf si le mot clé <literal>ONLY</literal> précède le nom de la table. Néanmoins, |
|---|
| 132 | la référence produit seulement les colonnes qui apparaissent dans la table |
|---|
| 133 | nommée... toute colonne ajoutée dans une sous-table est ignorée. |
|---|
| 134 | </para> |
|---|
| 135 | |
|---|
| 136 | <sect3 id="queries-join"> |
|---|
| 137 | <title>Tables jointes</title> |
|---|
| 138 | |
|---|
| 139 | <indexterm zone="queries-join"> |
|---|
| 140 | <primary>join</primary> |
|---|
| 141 | </indexterm> |
|---|
| 142 | |
|---|
| 143 | <para> |
|---|
| 144 | Une table jointe est une table dérivée de deux autres tables (réelles ou |
|---|
| 145 | dérivées) suivant les règles du type de jointure particulier. Les |
|---|
| 146 | jointures internes (inner), externes (outer) et croisées (cross) sont |
|---|
| 147 | disponibles. |
|---|
| 148 | </para> |
|---|
| 149 | |
|---|
| 150 | <variablelist> |
|---|
| 151 | <title>Types de jointures</title> |
|---|
| 152 | |
|---|
| 153 | <varlistentry> |
|---|
| 154 | <term>Jointure croisée (cross join)</term> |
|---|
| 155 | |
|---|
| 156 | <listitem> |
|---|
| 157 | <indexterm> |
|---|
| 158 | <primary>jointure</primary> |
|---|
| 159 | <secondary>croisée</secondary> |
|---|
| 160 | </indexterm> |
|---|
| 161 | |
|---|
| 162 | <indexterm> |
|---|
| 163 | <primary>join</primary> |
|---|
| 164 | <secondary>cross</secondary> |
|---|
| 165 | </indexterm> |
|---|
| 166 | |
|---|
| 167 | <indexterm> |
|---|
| 168 | <primary>jointure croisée</primary> |
|---|
| 169 | </indexterm> |
|---|
| 170 | |
|---|
| 171 | <indexterm> |
|---|
| 172 | <primary>crossed joind</primary> |
|---|
| 173 | </indexterm> |
|---|
| 174 | |
|---|
| 175 | <synopsis><replaceable>T1</replaceable> CROSS JOIN <replaceable>T2</replaceable></synopsis> |
|---|
| 176 | |
|---|
| 177 | <para> |
|---|
| 178 | Pour chaque combinaison possible de lignes provenant de |
|---|
| 179 | <replaceable>T1</replaceable> et <replaceable>T2</replaceable> |
|---|
| 180 | (c'est-à-dire un produit cartésien), la table jointe contiendra |
|---|
| 181 | une ligne disposant de toutes les colonnes de |
|---|
| 182 | <replaceable>T1</replaceable> suivies par toutes les colonnes de |
|---|
| 183 | <replaceable>T2</replaceable>. |
|---|
| 184 | Si les tables ont respectivement N et M lignes, la table jointe en |
|---|
| 185 | aura N * M. |
|---|
| 186 | </para> |
|---|
| 187 | |
|---|
| 188 | <para> |
|---|
| 189 | <literal>FROM <replaceable>T1</replaceable> CROSS JOIN |
|---|
| 190 | <replaceable>T2</replaceable></literal> est équivalent à |
|---|
| 191 | <literal>FROM <replaceable>T1</replaceable>, |
|---|
| 192 | <replaceable>T2</replaceable></literal>. C'est aussi équivalent à |
|---|
| 193 | <literal>FROM <replaceable>T1</replaceable> INNER JOIN |
|---|
| 194 | <replaceable>T2</replaceable> ON TRUE</literal> (voir ci-dessous). |
|---|
| 195 | </para> |
|---|
| 196 | </listitem> |
|---|
| 197 | </varlistentry> |
|---|
| 198 | |
|---|
| 199 | <varlistentry> |
|---|
| 200 | <term>Jointures qualifiées (qualified joins)</term> |
|---|
| 201 | |
|---|
| 202 | <listitem> |
|---|
| 203 | |
|---|
| 204 | <indexterm> |
|---|
| 205 | <primary>join</primary> |
|---|
| 206 | <secondary>outer</secondary> |
|---|
| 207 | </indexterm> |
|---|
| 208 | |
|---|
| 209 | <indexterm> |
|---|
| 210 | <primary>outer join</primary> |
|---|
| 211 | </indexterm> |
|---|
| 212 | |
|---|
| 213 | <indexterm> |
|---|
| 214 | <primary>jointure</primary> |
|---|
| 215 | <secondary>externe</secondary> |
|---|
| 216 | </indexterm> |
|---|
| 217 | |
|---|
| 218 | <indexterm> |
|---|
| 219 | <primary>jointure externe</primary> |
|---|
| 220 | </indexterm> |
|---|
| 221 | |
|---|
| 222 | <synopsis><replaceable>T1</replaceable> { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable> ON <replaceable>expression_booleenne</replaceable> |
|---|
| 223 | <replaceable>T1</replaceable> { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable> USING ( <replaceable>liste des colonnes jointes</replaceable> ) |
|---|
| 224 | <replaceable>T1</replaceable> NATURAL { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable></synopsis> |
|---|
| 225 | |
|---|
| 226 | <para> |
|---|
| 227 | Les mots <literal>INNER</literal> et |
|---|
| 228 | <literal>OUTER</literal> sont optionnels dans toutes les formes. |
|---|
| 229 | <literal>INNER</literal> est la valeur par défaut ; |
|---|
| 230 | <literal>LEFT</literal>, <literal>RIGHT</literal> et |
|---|
| 231 | <literal>FULL</literal> impliquent une jointure externe. |
|---|
| 232 | </para> |
|---|
| 233 | |
|---|
| 234 | <para> |
|---|
| 235 | La <firstterm>condition de la jointure</firstterm> est spécifiée dans |
|---|
| 236 | la clause <literal>ON</literal> ou <literal>USING</literal>, ou implicitement par le |
|---|
| 237 | mot <literal>NATURAL</literal>. La condition de jointure détermine les lignes |
|---|
| 238 | des deux tables source considérées comme <quote>correspondante</quote>, |
|---|
| 239 | comme l'explique le paragraphe ci-dessous. |
|---|
| 240 | </para> |
|---|
| 241 | |
|---|
| 242 | <para> |
|---|
| 243 | La clause <literal>ON</literal> est le type le plus général de condition de |
|---|
| 244 | jointure : il prend une expression booléenne du même genre que |
|---|
| 245 | celle utilisée dans une clause <literal>WHERE</literal>. Une paires de lignes |
|---|
| 246 | de <replaceable>T1</replaceable> et <replaceable>T2</replaceable> correspondent si |
|---|
| 247 | l'expression <literal>ON</literal> est évaluée à vraie (true) pour ces deux |
|---|
| 248 | lignes. |
|---|
| 249 | </para> |
|---|
| 250 | |
|---|
| 251 | <para> |
|---|
| 252 | <literal>USING</literal> est la notation raccourcie : elle prend une |
|---|
| 253 | liste de noms de colonnes, séparés par des virgules, que les tables |
|---|
| 254 | jointes ont en commun, et forme une condition de jointure spécifiant |
|---|
| 255 | l'égalité de chacune de ces paires de colonnes. De plus, la sortie de |
|---|
| 256 | <literal>JOIN USING</literal> a une colonne pour chaque paires égales des |
|---|
| 257 | colonnes en entrée, suivies par toutes les autres colonnes de chaque |
|---|
| 258 | table. Du coup, <literal>USING (a, b, c)</literal> est équivalent à |
|---|
| 259 | <literal>ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)</literal> avec |
|---|
| 260 | l'exception que si <literal>ON</literal> est utilisé, il y aura deux colonnes |
|---|
| 261 | <literal>a</literal>, <literal>b</literal>, puis <literal>c</literal> dans le résultat, alors |
|---|
| 262 | qu'avec <literal>USING</literal>, il n'y en aurait eu qu'une de chaque |
|---|
| 263 | (et elles apparaîtront en premier si <command>SELECT *</command> est |
|---|
| 264 | utilisé). |
|---|
| 265 | </para> |
|---|
| 266 | |
|---|
| 267 | <para> |
|---|
| 268 | <indexterm> |
|---|
| 269 | <primary>join</primary> |
|---|
| 270 | <secondary>natural</secondary> |
|---|
| 271 | </indexterm> |
|---|
| 272 | <indexterm> |
|---|
| 273 | <primary>natural join</primary> |
|---|
| 274 | </indexterm> |
|---|
| 275 | <indexterm> |
|---|
| 276 | <primary>jointure</primary> |
|---|
| 277 | <secondary>naturelle</secondary> |
|---|
| 278 | </indexterm> |
|---|
| 279 | <indexterm> |
|---|
| 280 | <primary>jointure naturelle</primary> |
|---|
| 281 | </indexterm> |
|---|
| 282 | Enfin, <literal>NATURAL</literal> est un format raccourci de |
|---|
| 283 | <literal>USING</literal> : il forme une liste <literal>USING</literal> |
|---|
| 284 | consistant de tous les noms de colonnes apparaissant à la fois dans |
|---|
| 285 | les deux tables en entrée. Comme avec <literal>USING</literal>, ces colonnes |
|---|
| 286 | apparaissent seulement une fois dans la table de sortie. |
|---|
| 287 | </para> |
|---|
| 288 | |
|---|
| 289 | <para> |
|---|
| 290 | Les types possibles de jointures qualifiées sont : |
|---|
| 291 | |
|---|
| 292 | <variablelist> |
|---|
| 293 | <varlistentry> |
|---|
| 294 | <term><literal>INNER JOIN</literal></term> |
|---|
| 295 | |
|---|
| 296 | <listitem> |
|---|
| 297 | <para> |
|---|
| 298 | Pour chaque ligne R1 de T1, la table jointe a une ligne pour chaque |
|---|
| 299 | ligne de T2 satisfaisant la condition de jointure avec R1. |
|---|
| 300 | </para> |
|---|
| 301 | </listitem> |
|---|
| 302 | </varlistentry> |
|---|
| 303 | |
|---|
| 304 | <varlistentry> |
|---|
| 305 | <term><literal>LEFT OUTER JOIN</literal></term> |
|---|
| 306 | |
|---|
| 307 | <listitem> |
|---|
| 308 | <indexterm> |
|---|
| 309 | <primary>join</primary> |
|---|
| 310 | <secondary>left</secondary> |
|---|
| 311 | </indexterm> |
|---|
| 312 | |
|---|
| 313 | <indexterm> |
|---|
| 314 | <primary>left join</primary> |
|---|
| 315 | </indexterm> |
|---|
| 316 | |
|---|
| 317 | <indexterm> |
|---|
| 318 | <primary>jointure</primary> |
|---|
| 319 | <secondary>gauche</secondary> |
|---|
| 320 | </indexterm> |
|---|
| 321 | |
|---|
| 322 | <indexterm> |
|---|
| 323 | <primary>jointure gauche</primary> |
|---|
| 324 | </indexterm> |
|---|
| 325 | |
|---|
| 326 | <para> |
|---|
| 327 | Tout d'abord, une jointure interne est réalisée. Puis, pour chaque |
|---|
| 328 | ligne de T1 qui ne satisfait pas la condition de jointure avec |
|---|
| 329 | les lignes de T2, une ligne jointe est ajoutée avec des valeurs |
|---|
| 330 | NULL dans les colonnes de T2. Du coup, la table jointe a toujours au moins |
|---|
| 331 | une ligne pour chaque ligne de T1 quelque soient les conditions. |
|---|
| 332 | </para> |
|---|
| 333 | </listitem> |
|---|
| 334 | </varlistentry> |
|---|
| 335 | |
|---|
| 336 | <varlistentry> |
|---|
| 337 | <term><literal>RIGHT OUTER JOIN</literal></term> |
|---|
| 338 | |
|---|
| 339 | <listitem> |
|---|
| 340 | <indexterm> |
|---|
| 341 | <primary>join</primary> |
|---|
| 342 | <secondary>right</secondary> |
|---|
| 343 | </indexterm> |
|---|
| 344 | |
|---|
| 345 | <indexterm> |
|---|
| 346 | <primary>right join</primary> |
|---|
| 347 | </indexterm> |
|---|
| 348 | |
|---|
| 349 | <indexterm> |
|---|
| 350 | <primary>jointure</primary> |
|---|
| 351 | <secondary>droite</secondary> |
|---|
| 352 | </indexterm> |
|---|
| 353 | |
|---|
| 354 | <indexterm> |
|---|
| 355 | <primary>jointure droite</primary> |
|---|
| 356 | </indexterm> |
|---|
| 357 | |
|---|
| 358 | <para> |
|---|
| 359 | Tout d'abord, une jointure interne est réalisée. Puis, pour chaque |
|---|
| 360 | ligne de T2 qui ne satisfait pas la condition de jointure avec les |
|---|
| 361 | lignes de T1, une ligne jointe est ajoutée avec des valeurs NULL |
|---|
| 362 | dans les colonnes de T1. C'est l'inverse d'une jointure gauche : |
|---|
| 363 | la table résultante aura toujours une ligne pour chaque ligne de T2 quelque |
|---|
| 364 | soient les conditions. |
|---|
| 365 | </para> |
|---|
| 366 | </listitem> |
|---|
| 367 | </varlistentry> |
|---|
| 368 | |
|---|
| 369 | <varlistentry> |
|---|
| 370 | <term><literal>FULL OUTER JOIN</literal></term> |
|---|
| 371 | |
|---|
| 372 | <listitem> |
|---|
| 373 | <para> |
|---|
| 374 | Tout d'abord, une jointure interne est réalisée. Puis, pour chaque |
|---|
| 375 | ligne de T1 qui ne satisfait pas la condition de jointure avec les |
|---|
| 376 | lignes de T2, une ligne jointe est ajoutée avec des valeurs NULL dans |
|---|
| 377 | les colonnes de T2. De plus, pour chaque ligne de T2 qui ne satisfait |
|---|
| 378 | pas la condition de jointure avec les lignes de T1, une ligne jointe |
|---|
| 379 | est ajoutée avec des valeurs NULL dans les colonnes de T1. |
|---|
| 380 | </para> |
|---|
| 381 | </listitem> |
|---|
| 382 | </varlistentry> |
|---|
| 383 | </variablelist> |
|---|
| 384 | </para> |
|---|
| 385 | </listitem> |
|---|
| 386 | </varlistentry> |
|---|
| 387 | </variablelist> |
|---|
| 388 | |
|---|
| 389 | <para> |
|---|
| 390 | Les jointures de tous les types peuvent être chaînées ensemble ou |
|---|
| 391 | imbriquées : soit les deux soit une des deux, parmi |
|---|
| 392 | <replaceable>T1</replaceable> et <replaceable>T2</replaceable>, peuvent |
|---|
| 393 | être des tables. Les parenthèses peuvent être utilisées autour des clauses |
|---|
| 394 | <literal>JOIN</literal> pour contrôler l'ordre de jointure. En l'absence de |
|---|
| 395 | parenthèses, les clauses <literal>JOIN</literal> sont imbriquées de gauche à |
|---|
| 396 | droite. |
|---|
| 397 | </para> |
|---|
| 398 | |
|---|
| 399 | <para> |
|---|
| 400 | Pour rassembler tout ceci, supposons que nous avons une table |
|---|
| 401 | <literal>t1</literal> : |
|---|
| 402 | <programlisting> no | nom |
|---|
| 403 | ----+------ |
|---|
| 404 | 1 | a |
|---|
| 405 | 2 | b |
|---|
| 406 | 3 | c</programlisting> |
|---|
| 407 | et une table <literal>t2</literal> : |
|---|
| 408 | <programlisting> no | valeur |
|---|
| 409 | ----+------- |
|---|
| 410 | 1 | xxx |
|---|
| 411 | 3 | yyy |
|---|
| 412 | 5 | zzz</programlisting> |
|---|
| 413 | nous obtenons les résultats suivants pour les différentes jointures : |
|---|
| 414 | <screen><prompt>=></prompt> <userinput>SELECT * FROM t1 CROSS JOIN t2;</userinput> |
|---|
| 415 | no | nom | no | valeur |
|---|
| 416 | ----+-----+----+------- |
|---|
| 417 | 1 | a | 1 | xxx |
|---|
| 418 | 1 | a | 3 | yyy |
|---|
| 419 | 1 | a | 5 | zzz |
|---|
| 420 | 2 | b | 1 | xxx |
|---|
| 421 | 2 | b | 3 | yyy |
|---|
| 422 | 2 | b | 5 | zzz |
|---|
| 423 | 3 | c | 1 | xxx |
|---|
| 424 | 3 | c | 3 | yyy |
|---|
| 425 | 3 | c | 5 | zzz |
|---|
| 426 | (9 rows) |
|---|
| 427 | |
|---|
| 428 | <prompt>=></prompt> <userinput>SELECT * FROM t1 INNER JOIN t2 ON t1.no = t2.no;</userinput> |
|---|
| 429 | no | nom | no | valeur |
|---|
| 430 | ----+-----+----+------- |
|---|
| 431 | 1 | a | 1 | xxx |
|---|
| 432 | 3 | c | 3 | yyy |
|---|
| 433 | (2 rows) |
|---|
| 434 | |
|---|
| 435 | <prompt>=></prompt> <userinput>SELECT * FROM t1 INNER JOIN t2 USING (no);</userinput> |
|---|
| 436 | no | nom | valeur |
|---|
| 437 | ----+-----+------- |
|---|
| 438 | 1 | a | xxx |
|---|
| 439 | 3 | c | yyy |
|---|
| 440 | (2 rows) |
|---|
| 441 | |
|---|
| 442 | <prompt>=></prompt> <userinput>SELECT * FROM t1 NATURAL INNER JOIN t2;</userinput> |
|---|
| 443 | no | nom | valeur |
|---|
| 444 | ----+-----+------- |
|---|
| 445 | 1 | a | xxx |
|---|
| 446 | 3 | c | yyy |
|---|
| 447 | (2 rows) |
|---|
| 448 | |
|---|
| 449 | <prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 ON t1.no = t2.no;</userinput> |
|---|
| 450 | no | nom | no | valeur |
|---|
| 451 | ----+-----+----+------- |
|---|
| 452 | 1 | a | 1 | xxx |
|---|
| 453 | 2 | b | | |
|---|
| 454 | 3 | c | 3 | yyy |
|---|
| 455 | (3 rows) |
|---|
| 456 | |
|---|
| 457 | <prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 USING (no);</userinput> |
|---|
| 458 | no | nom | valeur |
|---|
| 459 | ----+-----+------- |
|---|
| 460 | 1 | a | xxx |
|---|
| 461 | 2 | b | |
|---|
| 462 | 3 | c | yyy |
|---|
| 463 | (3 rows) |
|---|
| 464 | |
|---|
| 465 | <prompt>=></prompt> <userinput>SELECT * FROM t1 RIGHT JOIN t2 ON t1.no = t2.no;</userinput> |
|---|
| 466 | no | nom | no | valeur |
|---|
| 467 | ----+-----+----+------- |
|---|
| 468 | 1 | a | 1 | xxx |
|---|
| 469 | 3 | c | 3 | yyy |
|---|
| 470 | | | 5 | zzz |
|---|
| 471 | (3 rows) |
|---|
| 472 | |
|---|
| 473 | <prompt>=></prompt> <userinput>SELECT * FROM t1 FULL JOIN t2 ON t1.no = t2.no;</userinput> |
|---|
| 474 | no | nom | no | valeur |
|---|
| 475 | ----+-----+----+------- |
|---|
| 476 | 1 | a | 1 | xxx |
|---|
| 477 | 2 | b | | |
|---|
| 478 | 3 | c | 3 | yyy |
|---|
| 479 | | | 5 | zzz |
|---|
| 480 | (4 rows)</screen> |
|---|
| 481 | </para> |
|---|
| 482 | |
|---|
| 483 | <para> |
|---|
| 484 | La condition de jointure spécifiée avec <literal>ON</literal> peut aussi contenir |
|---|
| 485 | des conditions sans relation directe avec la jointure. Ceci est utile |
|---|
| 486 | pour quelques requêtes mais son utilisation doit avoir été réfléchie. Par |
|---|
| 487 | exemple : |
|---|
| 488 | <screen><prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 ON t1.no = t2.no AND t2.valeur = 'xxx';</userinput> |
|---|
| 489 | no | nom | no | valeur |
|---|
| 490 | ----+-----+----+------- |
|---|
| 491 | 1 | a | 1 | xxx |
|---|
| 492 | 2 | b | | |
|---|
| 493 | 3 | c | | |
|---|
| 494 | (3 rows)</screen> |
|---|
| 495 | Notez que placer la restriction dans la clause <literal>WHERE</literal> |
|---|
| 496 | donne un résultat différent : |
|---|
| 497 | <screen> |
|---|
| 498 | <prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = 'xxx';</userinput> |
|---|
| 499 | num | name | num | value |
|---|
| 500 | -----+------+-----+------- |
|---|
| 501 | 1 | a | 1 | xxx |
|---|
| 502 | (1 row) |
|---|
| 503 | </screen> |
|---|
| 504 | Ceci est dû au fait qu'une restriction placée dans la clause |
|---|
| 505 | <literal>ON</literal> est traitée <emphasis>avant</emphasis> la jointure |
|---|
| 506 | alors qu'une restriction placée dans la clause <literal>WHERE</literal> |
|---|
| 507 | est traitée <emphasis>après</emphasis> la jointure. |
|---|
| 508 | </para> |
|---|
| 509 | </sect3> |
|---|
| 510 | |
|---|
| 511 | <sect3 id="queries-table-aliases"> |
|---|
| 512 | <title>Alias de table et de colonne</title> |
|---|
| 513 | |
|---|
| 514 | <indexterm zone="queries-table-aliases"> |
|---|
| 515 | <primary>alias</primary> |
|---|
| 516 | <secondary>dans la clause FROM</secondary> |
|---|
| 517 | </indexterm> |
|---|
| 518 | |
|---|
| 519 | <indexterm> |
|---|
| 520 | <primary>label</primary> |
|---|
| 521 | <see>alias</see> |
|---|
| 522 | </indexterm> |
|---|
| 523 | |
|---|
| 524 | <para> |
|---|
| 525 | Un nom temporaire peut être donné aux tables et aux références de tables |
|---|
| 526 | complexe, qui sera ensuite utilisé pour référencer la table dérivée dans la |
|---|
| 527 | suite de la requête. Cela s'appelle un <firstterm>alias de |
|---|
| 528 | table</firstterm>. |
|---|
| 529 | </para> |
|---|
| 530 | |
|---|
| 531 | <para> |
|---|
| 532 | Pour créer un alias de table, écrivez |
|---|
| 533 | <synopsis>FROM <replaceable>reference_table</replaceable> AS <replaceable>alias</replaceable></synopsis> |
|---|
| 534 | ou |
|---|
| 535 | <synopsis>FROM <replaceable>reference_table</replaceable> <replaceable>alias</replaceable></synopsis> |
|---|
| 536 | Le mot clé <literal>AS</literal> n'est pas obligatoire. |
|---|
| 537 | <replaceable>alias</replaceable> peut être tout identifiant. |
|---|
| 538 | </para> |
|---|
| 539 | |
|---|
| 540 | <para> |
|---|
| 541 | Une application typique des alias de table est l'affectation d'identifieurs |
|---|
| 542 | courts pour les noms de tables longs, ce qui permet de garder des clauses de |
|---|
| 543 | jointures lisibles. Par exemple : |
|---|
| 544 | <programlisting>SELECT * FROM nom_de_table_tres_tres_long s |
|---|
| 545 | JOIN un_autre_nom_tres_long a ON s.id = a.no;</programlisting> |
|---|
| 546 | </para> |
|---|
| 547 | |
|---|
| 548 | <para> |
|---|
| 549 | L'alias devient le nouveau nom de référence de la table pour la requête |
|---|
| 550 | courante — il n'est plus possible de référencer la table avec son nom |
|---|
| 551 | d'origine. Du coup : |
|---|
| 552 | <programlisting>SELECT * FROM ma_table AS m WHERE ma_table.a > 5;</programlisting> |
|---|
| 553 | n'est pas valide suivant le standard SQL. Dans |
|---|
| 554 | <productname>PostgreSQL</productname>, ceci amènera une erreur si la variable |
|---|
| 555 | <xref linkend="guc-add-missing-from"/> est désactivée (<literal>off</literal>, |
|---|
| 556 | valeur par défaut). |
|---|
| 557 | S'il est activé (<literal>on</literal>), une référence vers une table |
|---|
| 558 | implicite sera ajoutée à la clause <literal>FROM</literal>, de façon à ce que |
|---|
| 559 | la requête soit exécutée comme si elle était écrite ainsi : |
|---|
| 560 | <programlisting>SELECT * FROM ma_table AS m, ma_table AS ma_table WHERE ma_table.a > 5;</programlisting> |
|---|
| 561 | Cela résultera en une jointure croisée, ce qui n'est habituellement pas |
|---|
| 562 | ce que vous voulez. |
|---|
| 563 | </para> |
|---|
| 564 | |
|---|
| 565 | <para> |
|---|
| 566 | Les alias de table sont disponibles principalement pour aider à l'écriture |
|---|
| 567 | de requête mais ils deviennent nécessaires pour joindre une table avec |
|---|
| 568 | elle-même, par exemple : |
|---|
| 569 | <programlisting>SELECT * FROM personnes AS mere JOIN personnes AS enfant ON mere.id = enfant.mere_id; |
|---|
| 570 | </programlisting> |
|---|
| 571 | De plus, un alias est requis si la référence de la table est une |
|---|
| 572 | sous-requête (voir la <xref linkend="queries-subqueries"/>). |
|---|
| 573 | </para> |
|---|
| 574 | |
|---|
| 575 | <para> |
|---|
| 576 | Les parenthèses sont utilisées pour résoudre les ambiguïtés. Dans l'exemple |
|---|
| 577 | suivant, la première instruction affecte l'alias <literal>b</literal> à la |
|---|
| 578 | deuxième instance de <literal>ma_table</literal> mais la deuxième instruction |
|---|
| 579 | affecte l'alias au résultat de la jonction : |
|---|
| 580 | <programlisting>SELECT * FROM ma_table AS a CROSS JOIN ma_table AS b ... |
|---|
| 581 | SELECT * FROM (ma_table AS a CROSS JOIN ma_table) AS b ...</programlisting> |
|---|
| 582 | </para> |
|---|
| 583 | |
|---|
| 584 | <para> |
|---|
| 585 | Une autre forme d'alias de tables donne des noms temporaires aux colonnes |
|---|
| 586 | de la table ainsi qu'à la table : |
|---|
| 587 | <synopsis>FROM <replaceable>reference_table</replaceable> <optional>AS</optional> <replaceable>alias</replaceable> ( <replaceable>colonne1</replaceable> <optional>, <replaceable>colonne2</replaceable> <optional>, ...</optional></optional> )</synopsis> |
|---|
| 588 | Si le nombre d'alias de colonnes spécifié est plus petit que le nombre |
|---|
| 589 | de colonnes dont dispose la table réelle, les colonnes suivantes ne sont |
|---|
| 590 | pas renommées. Cette syntaxe est particulièrement utile dans le cas de |
|---|
| 591 | jointure avec la même table ou dans le cas de sous-requêtes. |
|---|
| 592 | </para> |
|---|
| 593 | |
|---|
| 594 | <para> |
|---|
| 595 | Quand un alias est appliqué à la sortie d'une clause <literal>JOIN</literal>, |
|---|
| 596 | l'alias cache le nom original référencé à l'intérieur du |
|---|
| 597 | <literal>JOIN</literal>. Par exemple : |
|---|
| 598 | <programlisting>SELECT a.* FROM ma_table AS a JOIN ta_table AS b ON ...</programlisting> |
|---|
| 599 | est du SQL valide mais : |
|---|
| 600 | <programlisting>SELECT a.* FROM (ma_table AS a JOIN ta_table AS b ON ...) AS c</programlisting> |
|---|
| 601 | n'est pas valide l'alias de table <literal>a</literal> n'est pas visible |
|---|
| 602 | en dehors de l'alias <literal>c</literal>. |
|---|
| 603 | </para> |
|---|
| 604 | </sect3> |
|---|
| 605 | |
|---|
| 606 | <sect3 id="queries-subqueries"> |
|---|
| 607 | <title>Sous-requêtes</title> |
|---|
| 608 | |
|---|
| 609 | <indexterm zone="queries-subqueries"> |
|---|
| 610 | <primary>sous-requête</primary> |
|---|
| 611 | </indexterm> |
|---|
| 612 | |
|---|
| 613 | <para> |
|---|
| 614 | Une sous-requête spécifiant une table dérivée doit être enfermée |
|---|
| 615 | dans des parenthèses et <emphasis>doit</emphasis> se voir affecté un alias |
|---|
| 616 | de table (voir la <xref linkend="queries-table-aliases"/>). Par |
|---|
| 617 | exemple : |
|---|
| 618 | <programlisting>FROM (SELECT * FROM table1) AS nom_alias</programlisting> |
|---|
| 619 | </para> |
|---|
| 620 | |
|---|
| 621 | <para> |
|---|
| 622 | Cet exemple est équivalent à <literal>FROM table1 AS |
|---|
| 623 | nom_alias</literal>. Des cas plus intéressants, qui ne peuvent pas être |
|---|
| 624 | réduit à une jointure pleine, surviennent quand la sous-requête implique un |
|---|
| 625 | groupement ou un agrégat. |
|---|
| 626 | </para> |
|---|
| 627 | |
|---|
| 628 | <para> |
|---|
| 629 | Uns sous-requête peut aussi être une liste <command>VALUES</command> : |
|---|
| 630 | <programlisting> |
|---|
| 631 | FROM (VALUES ('anne', 'smith'), ('bob', 'jones'), ('joe', 'blow')) |
|---|
| 632 | AS noms(prenom, nom) |
|---|
| 633 | </programlisting> |
|---|
| 634 | De nouveau, un alias de table est requis. Affecter des noms d'alias aux |
|---|
| 635 | colonnes de la liste <command>VALUES</command> est en option mais c'est |
|---|
| 636 | une bonne pratique. Pour plus d'informations, voir |
|---|
| 637 | <xref linkend="queries-values"/>. |
|---|
| 638 | </para> |
|---|
| 639 | </sect3> |
|---|
| 640 | |
|---|
| 641 | <sect3 id="queries-tablefunctions"> |
|---|
| 642 | <title>Fonctions de table</title> |
|---|
| 643 | |
|---|
| 644 | <indexterm zone="queries-tablefunctions"><primary>fonction de table</primary></indexterm> |
|---|
| 645 | |
|---|
| 646 | <indexterm zone="queries-tablefunctions"> |
|---|
| 647 | <primary>fonction</primary> |
|---|
| 648 | <secondary>dans la clause FROM</secondary> |
|---|
| 649 | </indexterm> |
|---|
| 650 | |
|---|
| 651 | <para> |
|---|
| 652 | Les fonctions de table sont des fonctions produisant un ensemble de |
|---|
| 653 | lignes composées de types de données de base (types scalaires) ou de types |
|---|
| 654 | de données composites (lignes de table). Elles sont utilisées comme une |
|---|
| 655 | table, une vue ou une sous-requête de la clause <literal>FROM</literal> d'une |
|---|
| 656 | requête. Les colonnes renvoyées par les fonctions de table peuvent être |
|---|
| 657 | incluses dans une clause <literal>SELECT</literal>, <literal>JOIN</literal> ou |
|---|
| 658 | <literal>WHERE</literal> de la même manière qu'une colonne de table, vue ou |
|---|
| 659 | sous-requête. |
|---|
| 660 | </para> |
|---|
| 661 | |
|---|
| 662 | <para> |
|---|
| 663 | Si une fonction de table renvoie un type de données de base, la nom de la |
|---|
| 664 | colonne de résultat correspond à celui de la fonction. Si la fonction |
|---|
| 665 | renvoie un type composite, les colonnes résultantes ont le même nom que |
|---|
| 666 | les attributs individuels du type. |
|---|
| 667 | </para> |
|---|
| 668 | |
|---|
| 669 | <para> |
|---|
| 670 | Une fonction de table peut avoir un alias dans la clause |
|---|
| 671 | <literal>FROM</literal> mais elle peut être laissée sans alias. Si une |
|---|
| 672 | fonction est utilisée dans la clause <literal>FROM</literal> sans alias, le nom de |
|---|
| 673 | la fonction est utilisé comme nom de table résultante. |
|---|
| 674 | </para> |
|---|
| 675 | |
|---|
| 676 | <para> |
|---|
| 677 | Quelques exemples : |
|---|
| 678 | <programlisting>CREATE TABLE truc (trucid int, trucsousid int, trucnom text); |
|---|
| 679 | |
|---|
| 680 | CREATE FUNCTION recuptruc(int) RETURNS SETOF foo AS $$ |
|---|
| 681 | SELECT * FROM truc WHERE trucid = $1; |
|---|
| 682 | $$ LANGUAGE SQL; |
|---|
| 683 | |
|---|
| 684 | SELECT * FROM recuptruc(1) AS t1; |
|---|
| 685 | |
|---|
| 686 | SELECT * FROM truc |
|---|
| 687 | WHERE trucsousid IN ( |
|---|
| 688 | SELECT trucsousid |
|---|
| 689 | FROM recuptruc(truc.trucid) z |
|---|
| 690 | WHERE z.trucid = truc.trucid); |
|---|
| 691 | |
|---|
| 692 | CREATE VIEW vue_recuptruc AS SELECT * FROM recuptruc(1); |
|---|
| 693 | SELECT * FROM vue_recuptruc;</programlisting> |
|---|
| 694 | </para> |
|---|
| 695 | |
|---|
| 696 | <para> |
|---|
| 697 | Dans certains cas, il est utile de définir des fonctions de table pouvant |
|---|
| 698 | renvoyer des ensembles de colonnes différentes suivant la façon dont elles |
|---|
| 699 | sont appelées. Pour supporter ceci, la fonction de table est déclarée comme |
|---|
| 700 | renvoyant le pseudotype <type>record</type>. Quand une telle fonction est |
|---|
| 701 | utilisée dans une requête, la structure de ligne attendue doit être |
|---|
| 702 | spécifiée dans la requête elle-même, de façon à ce que le système sache |
|---|
| 703 | comment analyser et planifier la requête. Considérez cet exemple : |
|---|
| 704 | <programlisting>SELECT * |
|---|
| 705 | FROM dblink('dbname=mabd', 'SELECT proname, prosrc FROM pg_proc') |
|---|
| 706 | AS t1(proname nom, prosrc text) |
|---|
| 707 | WHERE proname LIKE 'bytea%';</programlisting> |
|---|
| 708 | La fonction <literal>dblink</literal> exécute une requête distante (voir |
|---|
| 709 | <filename>contrib/dblink</filename>). Elle déclare renvoyer le type |
|---|
| 710 | <type>record</type> car elle pourrait être utilisée pour tout type de requête. |
|---|
| 711 | L'ensemble de colonnes réelles doit être spécifié dans la requête |
|---|
| 712 | appelante de façon à ce que l'analyseur sache, par exemple, comment |
|---|
| 713 | étendre <literal>*</literal>. |
|---|
| 714 | </para> |
|---|
| 715 | </sect3> |
|---|
| 716 | </sect2> |
|---|
| 717 | |
|---|
| 718 | <sect2 id="queries-where"> |
|---|
| 719 | <title>Clause <literal>WHERE</literal></title> |
|---|
| 720 | |
|---|
| 721 | <indexterm zone="queries-where"> |
|---|
| 722 | <primary>WHERE</primary> |
|---|
| 723 | </indexterm> |
|---|
| 724 | |
|---|
| 725 | <para> |
|---|
| 726 | La syntaxe de la <xref linkend="sql-where" endterm="sql-where-title"/> est |
|---|
| 727 | <synopsis>WHERE <replaceable>condition_recherche</replaceable></synopsis> |
|---|
| 728 | où <replaceable>condition_recherche</replaceable> est toute expression de |
|---|
| 729 | valeur (voir la <xref linkend="sql-expressions"/>) renvoyant une valeur |
|---|
| 730 | de type <type>boolean</type>. |
|---|
| 731 | </para> |
|---|
| 732 | |
|---|
| 733 | <para> |
|---|
| 734 | Après le traitement de la clause <literal>FROM</literal>, chaque ligne de la |
|---|
| 735 | table virtuelle dérivée est vérifiée avec la condition de recherche. Si le |
|---|
| 736 | résultat de la vérification est positif (true), la ligne est conservée dans |
|---|
| 737 | la table de sortie, sinon (c'est-à-dire si le résultat est faux ou nul), la |
|---|
| 738 | ligne est abandonnée. La condition de recherche référence typiquement au |
|---|
| 739 | moins une colonne de la table générée dans la clause |
|---|
| 740 | <literal>FROM</literal> ; ceci n'est pas requis mais, dans le cas contraire, |
|---|
| 741 | la clause <literal>WHERE</literal> n'aurait aucune utilité. |
|---|
| 742 | </para> |
|---|
| 743 | |
|---|
| 744 | <note> |
|---|
| 745 | <para> |
|---|
| 746 | La condition de jointure d'une jointure interne peut être écrite soit dans |
|---|
| 747 | la clause <literal>WHERE</literal> soit dans la clause <literal>JOIN</literal>. Par |
|---|
| 748 | exemple, ces expressions de tables sont équivalentes : |
|---|
| 749 | <programlisting>FROM a, b WHERE a.id = b.id AND b.val > 5</programlisting> |
|---|
| 750 | et : |
|---|
| 751 | <programlisting>FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val > 5</programlisting> |
|---|
| 752 | ou même peut-être : |
|---|
| 753 | <programlisting>FROM a NATURAL JOIN b WHERE b.val > 5</programlisting> |
|---|
| 754 | Laquelle vous utilisez est plutôt une affaire de style. La syntaxe |
|---|
| 755 | <literal>JOIN</literal> dans la clause <literal>FROM</literal> n'est probablement pas |
|---|
| 756 | aussi portable vers les autres systèmes de gestion de bases de données SQL, |
|---|
| 757 | même si cela fait partie du standard SQL. |
|---|
| 758 | Pour les jointures externes, il n'y a pas d'autres choix : elles |
|---|
| 759 | doivent être faites dans la clause <literal>FROM</literal>. La clause |
|---|
| 760 | <literal>ON</literal> ou <literal>USING</literal> d'une jointure externe n'est |
|---|
| 761 | <emphasis>pas</emphasis> équivalente à une condition <literal>WHERE</literal> parce |
|---|
| 762 | qu'elle détermine l'ajout de lignes (pour les lignes qui ne correspondent |
|---|
| 763 | pas en entrée) ainsi que pour la suppression de lignes dans le résultat |
|---|
| 764 | final. |
|---|
| 765 | </para> |
|---|
| 766 | </note> |
|---|
| 767 | |
|---|
| 768 | <para> |
|---|
| 769 | Voici quelques exemples de clauses <literal>WHERE</literal> : |
|---|
| 770 | <programlisting>SELECT ... FROM fdt WHERE c1 > 5 |
|---|
| 771 | |
|---|
| 772 | SELECT ... FROM fdt WHERE c1 IN (1, 2, 3) |
|---|
| 773 | |
|---|
| 774 | SELECT ... FROM fdt WHERE c1 IN (SELECT c1 FROM t2) |
|---|
| 775 | |
|---|
| 776 | SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) |
|---|
| 777 | |
|---|
| 778 | SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100 |
|---|
| 779 | |
|---|
| 780 | SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)</programlisting> |
|---|
| 781 | <literal>fdt</literal> est la table dérivée dans la clause |
|---|
| 782 | <literal>FROM</literal>. Les lignes qui ne correspondent pas à la condition de |
|---|
| 783 | recherche de la clause <literal>WHERE</literal> sont éliminées de la table |
|---|
| 784 | <literal>fdt</literal>. Notez l'utilisation de sous-requêtes scalaires en |
|---|
| 785 | tant qu'expressions de valeurs. Comme n'importe quelle autre requête, les |
|---|
| 786 | sous-requêtes peuvent employer des expressions de tables complexes. Notez |
|---|
| 787 | aussi comment <literal>fdt</literal> est référencée dans les sous-requêtes. |
|---|
| 788 | Qualifier <literal>c1</literal> comme <literal>fdt.c1</literal> est seulement nécessaire |
|---|
| 789 | si <literal>c1</literal> est aussi le nom d'une colonne dans la table d'entrée |
|---|
| 790 | dérivée de la sous-requête. Mais qualifier le nom de colonne ajoute à la |
|---|
| 791 | clarté même lorsque cela n'est pas nécessaire. Cet exemple montre comment |
|---|
| 792 | le nom de colonne d'une requête externe est étendue dans les requêtes |
|---|
| 793 | internes. |
|---|
| 794 | </para> |
|---|
| 795 | </sect2> |
|---|
| 796 | |
|---|
| 797 | |
|---|
| 798 | <sect2 id="queries-group"> |
|---|
| 799 | <title>Clauses <literal>GROUP BY</literal> et |
|---|
| 800 | <literal>HAVING</literal></title> |
|---|
| 801 | |
|---|
| 802 | <indexterm zone="queries-group"> |
|---|
| 803 | <primary>GROUP BY</primary> |
|---|
| 804 | </indexterm> |
|---|
| 805 | |
|---|
| 806 | <indexterm zone="queries-group"> |
|---|
| 807 | <primary>groupement</primary> |
|---|
| 808 | </indexterm> |
|---|
| 809 | |
|---|
| 810 | <para> |
|---|
| 811 | Après avoir passé le filtre <literal>WHERE</literal>, la table d'entrée dérivée |
|---|
| 812 | peut être sujette à un regroupement en utilisant la clause <literal>GROUP |
|---|
| 813 | BY</literal> et à une élimination de groupe de lignes avec la clause |
|---|
| 814 | <literal>HAVING</literal>. |
|---|
| 815 | </para> |
|---|
| 816 | |
|---|
| 817 | <synopsis>SELECT <replaceable>liste_selection</replaceable> |
|---|
| 818 | FROM ... |
|---|
| 819 | <optional>WHERE ...</optional> |
|---|
| 820 | GROUP BY <replaceable>reference_colonne_regroupement</replaceable><optional>,<replaceable>reference_colonne_regroupement</replaceable></optional>...</synopsis> |
|---|
| 821 | |
|---|
| 822 | <para> |
|---|
| 823 | La <xref linkend="sql-groupby" endterm="sql-groupby-title"/> est |
|---|
| 824 | utilisée pour regrouper les lignes d'une table qui ont les mêmes valeurs |
|---|
| 825 | dans toutes les colonnes précisées. L'ordre dans lequel ces colonnes sont |
|---|
| 826 | indiquées importe peu. L'effet est de combiner chaque ensemble de lignes |
|---|
| 827 | partageant des valeurs communes en un seul groupe de ligne représentant |
|---|
| 828 | toutes les lignes du groupe. Ceci est fait pour éliminer les redondances dans |
|---|
| 829 | la sortie et/ou pour calculer les agrégats s'appliquant à ces groupes. Par |
|---|
| 830 | exemple : |
|---|
| 831 | <screen><prompt>=></prompt> <userinput>SELECT * FROM test1;</userinput> |
|---|
| 832 | x | y |
|---|
| 833 | ---+--- |
|---|
| 834 | a | 3 |
|---|
| 835 | c | 2 |
|---|
| 836 | b | 5 |
|---|
| 837 | a | 1 |
|---|
| 838 | (4 rows) |
|---|
| 839 | |
|---|
| 840 | <prompt>=></prompt> <userinput>SELECT x FROM test1 GROUP BY x;</userinput> |
|---|
| 841 | x |
|---|
| 842 | --- |
|---|
| 843 | a |
|---|
| 844 | b |
|---|
| 845 | c |
|---|
| 846 | (3 rows)</screen> |
|---|
| 847 | </para> |
|---|
| 848 | |
|---|
| 849 | <para> |
|---|
| 850 | Dans la seconde requête, nous n'aurions pas pu écrire <literal>SELECT * |
|---|
| 851 | FROM test1 GROUP BY x</literal> parce qu'il n'existe pas une seule valeur |
|---|
| 852 | pour la colonne <literal>y</literal> pouvant être associé avec chaque autre groupe. |
|---|
| 853 | Les colonnes de regroupement peuvent être référencées dans la liste de |
|---|
| 854 | sélection car elles ont une valeur constante unique par groupe. |
|---|
| 855 | </para> |
|---|
| 856 | |
|---|
| 857 | <para> |
|---|
| 858 | En général, si une table est groupée, les colonnes qui ne sont pas |
|---|
| 859 | listées dans le <literal>GROUP BY</literal> ne peuvent pas être référencées |
|---|
| 860 | sauf dans les expressions d'agrégats. Voici un exemple d'expressions |
|---|
| 861 | d'agrégat : |
|---|
| 862 | <screen><prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x;</userinput> |
|---|
| 863 | x | sum |
|---|
| 864 | ---+----- |
|---|
| 865 | a | 4 |
|---|
| 866 | b | 5 |
|---|
| 867 | c | 2 |
|---|
| 868 | (3 rows)</screen> |
|---|
| 869 | Ici, <literal>sum</literal> est la fonction d'agrégat qui calcule une seule |
|---|
| 870 | valeur pour le groupe entier. La <xref linkend="functions-aggregate"/> |
|---|
| 871 | propose plus d'informations sur les fonctions d'agrégats disponibles. |
|---|
| 872 | </para> |
|---|
| 873 | |
|---|
| 874 | <tip> |
|---|
| 875 | <para> |
|---|
| 876 | Le regroupement sans expressions d'agrégats calcule effectivement |
|---|
| 877 | l'ensemble les valeurs distinctes d'une colonne. Ceci peut aussi se faire |
|---|
| 878 | en utilisant la clause <literal>DISTINCT</literal> (voir la <xref |
|---|
| 879 | linkend="queries-distinct"/>). |
|---|
| 880 | </para> |
|---|
| 881 | </tip> |
|---|
| 882 | |
|---|
| 883 | <para> |
|---|
| 884 | Voici un autre exemple : il calcule les ventes totales pour chaque |
|---|
| 885 | produit (plutôt que le total des ventes sur tous les produits) : |
|---|
| 886 | <programlisting>SELECT produit_id, p.nom, (sum(v.unite) * p.prix) AS ventes |
|---|
| 887 | FROM produits p LEFT JOIN ventes v USING (produit_id) |
|---|
| 888 | GROUP BY produit_id, p.nom, p.prix;</programlisting> |
|---|
| 889 | Dans cet exemple, les colonnes <literal>produit_id</literal>, |
|---|
| 890 | <literal>p.nom</literal> et <literal>p.prix</literal> doivent être dans la |
|---|
| 891 | clause <literal>GROUP BY</literal> car elles sont référencées dans la liste de |
|---|
| 892 | sélection de la requête (suivant la façon dont est conçue la table |
|---|
| 893 | produits, le nom et le prix pourraient être totalement dépendants de l'ID du |
|---|
| 894 | produit, donc des regroupements supplémentaires pourraient théoriquement |
|---|
| 895 | être inutiles mais ceci n'est pas encore implémenté). La colonne |
|---|
| 896 | <literal>s.unite</literal> n'a pas besoin d'être dans la liste <literal>GROUP |
|---|
| 897 | BY</literal> car elle est seulement utilisée dans l'expression de l'agrégat |
|---|
| 898 | (<literal>sum(...)</literal>) représentant les ventes d'un produit. Pour |
|---|
| 899 | chaque produit, la requête renvoie une ligne de résumé sur les ventes de ce |
|---|
| 900 | produit. |
|---|
| 901 | </para> |
|---|
| 902 | |
|---|
| 903 | <para> |
|---|
| 904 | En SQL strict, <literal>GROUP BY</literal> peut seulement grouper les colonnes de |
|---|
| 905 | la table source mais <productname>PostgreSQL</productname> étend ceci en |
|---|
| 906 | autorisant <literal>GROUP BY</literal> à grouper aussi les colonnes de la liste de |
|---|
| 907 | sélection. Grouper par expressions de valeurs au lieu de simples noms de |
|---|
| 908 | colonnes est aussi permis. |
|---|
| 909 | </para> |
|---|
| 910 | |
|---|
| 911 | <indexterm> |
|---|
| 912 | <primary>HAVING</primary> |
|---|
| 913 | </indexterm> |
|---|
| 914 | |
|---|
| 915 | <para> |
|---|
| 916 | Si une table a été groupée en utilisant la clause <literal>GROUP |
|---|
| 917 | BY</literal> mais que seuls certains groupes sont intéressants, la clause |
|---|
| 918 | <literal>HAVING</literal> peut être utilisée, comme une clause |
|---|
| 919 | <literal>WHERE</literal>, pour éliminer les groupes du résultat. Voici la |
|---|
| 920 | syntaxe : |
|---|
| 921 | <synopsis>SELECT <replaceable>liste_selection</replaceable> FROM ... <optional>WHERE ...</optional> GROUP BY ... HAVING <replaceable>expression_booléenne</replaceable></synopsis> |
|---|
| 922 | Les expressions de la clause <literal>HAVING</literal> peuvent référer à la fois |
|---|
| 923 | aux expressions groupées et aux expressions non groupées (ce qui impliquent |
|---|
| 924 | nécessairement une fonction d'agrégat). |
|---|
| 925 | </para> |
|---|
| 926 | |
|---|
| 927 | <para> |
|---|
| 928 | Exemple : |
|---|
| 929 | <screen><prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;</userinput> |
|---|
| 930 | x | sum |
|---|
| 931 | ---+----- |
|---|
| 932 | a | 4 |
|---|
| 933 | b | 5 |
|---|
| 934 | (2 rows) |
|---|
| 935 | |
|---|
| 936 | <prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';</userinput> |
|---|
| 937 | x | sum |
|---|
| 938 | ---+----- |
|---|
| 939 | a | 4 |
|---|
| 940 | b | 5 |
|---|
| 941 | (2 rows)</screen> |
|---|
| 942 | </para> |
|---|
| 943 | |
|---|
| 944 | <para> |
|---|
| 945 | De nouveau, un exemple plus réaliste : |
|---|
| 946 | <programlisting>SELECT produit_id, p.nom, (sum(v.unite) * (p.prix - p.cout)) AS profit |
|---|
| 947 | FROM produits p LEFT JOIN ventes v USING (produit_id) |
|---|
| 948 | WHERE v.date > CURRENT_DATE - INTERVAL '4 weeks' |
|---|
| 949 | GROUP BY produit_id, p.nom, p.prix, p.cout |
|---|
| 950 | HAVING sum(p.prix * s.unite) > 5000;</programlisting> |
|---|
| 951 | Dans l'exemple ci-dessus, la clause <literal>WHERE</literal> sélectionne les |
|---|
| 952 | lignes par une colonne qui n'est pas groupée (l'expression est vraie |
|---|
| 953 | seulement pour les ventes des quatre dernières semaines) alors que la |
|---|
| 954 | clause <literal>HAVING</literal> restreint la sortie aux groupes dont le total des |
|---|
| 955 | ventes dépasse 5000. Notez que les expressions d'agrégats n'ont pas besoin |
|---|
| 956 | d'être identiques dans toutes les parties d'une requête. |
|---|
| 957 | </para> |
|---|
| 958 | |
|---|
| 959 | <para> |
|---|
| 960 | Si une requête contient des appels à des fonctions d'aggrégat, mais pas |
|---|
| 961 | de clause <literal>GROUP BY</literal>, le regroupement a toujours lieu : |
|---|
| 962 | le résultat est une seule ligne de regroupement (ou peut-être pas de ligne |
|---|
| 963 | du tout si la ligne unique est ensuite éliminée par la clause |
|---|
| 964 | <literal>HAVING</literal>). |
|---|
| 965 | Ceci est vrai aussi si elle comporte une clause <literal>HAVING</literal>, |
|---|
| 966 | même sans fonction d'aggrégat ou <literal>GROUP BY</literal>. |
|---|
| 967 | </para> |
|---|
| 968 | </sect2> |
|---|
| 969 | |
|---|
| 970 | <sect2 id="queries-window"> |
|---|
| 971 | <title>Traitement de fonctions Window</title> |
|---|
| 972 | |
|---|
| 973 | <indexterm zone="queries-window"> |
|---|
| 974 | <primary>fonction window</primary> |
|---|
| 975 | <secondary>ordre d'exécution</secondary> |
|---|
| 976 | </indexterm> |
|---|
| 977 | |
|---|
| 978 | <para> |
|---|
| 979 | Si la requête contient une des fonctions Window (voir |
|---|
| 980 | <xref linkend="tutorial-window"/> et <xref linkend="syntax-window-functions"/>), |
|---|
| 981 | ces fonctions sont évaluées après que soient effectués les regroupements, |
|---|
| 982 | les aggrégations, les filtrages par <literal>HAVING</literal>. |
|---|
| 983 | C'est-à-dire que si la requête comporte des aggrégat, <literal>GROUP |
|---|
| 984 | BY</literal> ou <literal>HAVING</literal>, alors les enregistrements vus |
|---|
| 985 | par les fonctions window sont les lignes regroupées à la place des |
|---|
| 986 | enregistrements originaux provenant de |
|---|
| 987 | <literal>FROM</literal>/<literal>WHERE</literal>. |
|---|
| 988 | </para> |
|---|
| 989 | |
|---|
| 990 | <para> |
|---|
| 991 | Quand des fonctions Window multiples sont utilisées, toutes les fonctions |
|---|
| 992 | Window ayant des clauses <literal>PARTITION BY</literal> et <literal>ORDER BY</literal> |
|---|
| 993 | syntaxiquement équivalentes seront à coup sûr évaluées en une seule passe sur |
|---|
| 994 | les données. |
|---|
| 995 | Par conséquent, elles verront le même ordre de tri, même si |
|---|
| 996 | <literal>ORDER BY</literal> ne détermine pas de façon unique un tri. |
|---|
| 997 | Toutefois, aucune garantie n'est faite à propos de l'évaluation de fonctions |
|---|
| 998 | ayant des spécifications de <literal>PARTITION BY</literal> ou |
|---|
| 999 | <literal>ORDER BY</literal> différentes. |
|---|
| 1000 | (Dans ces cas, une étape de tri est généralement nécessaire entre les passes |
|---|
| 1001 | d'évaluations de fonctions Window, et le tri ne garantit pas la préservation |
|---|
| 1002 | de l'ordre des enregistrements que son <literal>ORDER BY</literal> estime |
|---|
| 1003 | comme identiques.) |
|---|
| 1004 | </para> |
|---|
| 1005 | |
|---|
| 1006 | <para> |
|---|
| 1007 | À l'heure actuelle, les fonctions window nécessitent toujours des données |
|---|
| 1008 | pré-triées, ce qui fait que la sortie de la requête sera triée suivant |
|---|
| 1009 | l'une ou l'autre des clauses <literal>PARTITION BY</literal>/<literal>ORDER BY</literal> |
|---|
| 1010 | des fonctions Window. |
|---|
| 1011 | Il n'est toutefois pas recommandé de s'en servir. Utilisez une clause |
|---|
| 1012 | <literal>ORDER BY</literal> au plus haut niveau de la requête si vous |
|---|
| 1013 | voulez être sûr que vos résultats soient triés d'une certaine façon. |
|---|
| 1014 | </para> |
|---|
| 1015 | </sect2> |
|---|
| 1016 | </sect1> |
|---|
| 1017 | |
|---|
| 1018 | |
|---|
| 1019 | <sect1 id="queries-select-lists"> |
|---|
| 1020 | <title>Listes de sélection</title> |
|---|
| 1021 | |
|---|
| 1022 | <indexterm> |
|---|
| 1023 | <primary>SELECT</primary> |
|---|
| 1024 | <secondary>liste de sélection</secondary> |
|---|
| 1025 | </indexterm> |
|---|
| 1026 | |
|---|
| 1027 | <para> |
|---|
| 1028 | Comme montré dans la section précédente, l'expression de table pour la |
|---|
| 1029 | commande <command>SELECT</command> construit une table virtuelle intermédiaire |
|---|
| 1030 | en combinant les tables, vues, en éliminant les lignes, en groupant, etc. Cette |
|---|
| 1031 | table est finalement passée à la réalisation de la <firstterm>liste de |
|---|
| 1032 | sélection</firstterm>. Cette liste détermine les <emphasis>colonnes</emphasis> |
|---|
| 1033 | de la table intermédiaire à afficher. |
|---|
| 1034 | </para> |
|---|
| 1035 | |
|---|
| 1036 | <sect2 id="queries-select-list-items"> |
|---|
| 1037 | <title>Éléments de la liste de sélection</title> |
|---|
| 1038 | |
|---|
| 1039 | <indexterm> |
|---|
| 1040 | <primary>*</primary> |
|---|
| 1041 | </indexterm> |
|---|
| 1042 | |
|---|
| 1043 | <para> |
|---|
| 1044 | La forme la plus simple de liste de sélection est <literal>*</literal>. |
|---|
| 1045 | C'est un raccourci pour indiquer toutes les colonnes que l'expression de |
|---|
| 1046 | table produit. Sinon, une liste de sélection est une liste d'expressions |
|---|
| 1047 | de valeurs séparées par des virgules (comme défini dans la <xref |
|---|
| 1048 | linkend="sql-expressions"/>). Par exemple, cela pourrait être une liste des |
|---|
| 1049 | noms de colonnes : |
|---|
| 1050 | <programlisting>SELECT a, b, c FROM ...</programlisting> |
|---|
| 1051 | Les noms de colonnes <literal>a</literal>, <literal>b</literal> et <literal>c</literal> sont |
|---|
| 1052 | soit les noms actuels des colonnes des tables référencées dans la clause |
|---|
| 1053 | <literal>FROM</literal> soit les alias qui leur ont été donnés (voir l'explication |
|---|
| 1054 | dans <xref linkend="queries-table-aliases"/>). L'espace de nom disponible |
|---|
| 1055 | dans la liste de sélection est le même que dans la clause <literal>WHERE</literal> |
|---|
| 1056 | sauf si le regroupement est utilisé, auquel cas c'est le même que dans la |
|---|
| 1057 | clause <literal>HAVING</literal>. |
|---|
| 1058 | </para> |
|---|
| 1059 | |
|---|
| 1060 | <para> |
|---|
| 1061 | Si plus d'une table a une colonne du même nom, le nom de la table doit |
|---|
| 1062 | aussi être donné comme dans : |
|---|
| 1063 | <programlisting>SELECT tbl1.a, tbl2.a, tbl1.b FROM ...</programlisting> |
|---|
| 1064 | En travaillant avec plusieurs tables, il est aussi utile de demander toutes |
|---|
| 1065 | les colonnes d'une table particulière : |
|---|
| 1066 | <programlisting>SELECT tbl1.*, tbl2.a FROM ...</programlisting> |
|---|
| 1067 | (voir aussi la <xref linkend="queries-where"/>) |
|---|
| 1068 | </para> |
|---|
| 1069 | |
|---|
| 1070 | <para> |
|---|
| 1071 | Si une expression de valeur arbitraire est utilisée dans la liste de |
|---|
| 1072 | sélection, il ajoute conceptuellement une nouvelle colonne virtuelle dans la |
|---|
| 1073 | table renvoyée. L'expression de valeur est évaluée une fois pour chaque |
|---|
| 1074 | ligne avec une substitution des valeurs de lignes avec les références de |
|---|
| 1075 | colonnes. Mais les expressions de la liste de sélection n'ont pas à |
|---|
| 1076 | référencer les colonnes dans l'expression de la table de la clause |
|---|
| 1077 | <literal>FROM</literal> ; elles pourrait être des expressions arithmétiques |
|---|
| 1078 | constantes, par exemple. |
|---|
| 1079 | </para> |
|---|
| 1080 | </sect2> |
|---|
| 1081 | |
|---|
| 1082 | <sect2 id="queries-column-labels"> |
|---|
| 1083 | <title>Labels de colonnes</title> |
|---|
| 1084 | |
|---|
| 1085 | <indexterm zone="queries-column-labels"> |
|---|
| 1086 | <primary>alias</primary> |
|---|
| 1087 | <secondary>dans la liste de sélection</secondary> |
|---|
| 1088 | </indexterm> |
|---|
| 1089 | |
|---|
| 1090 | <para> |
|---|
| 1091 | Les entrées de la liste de sélection peuvent se voir affecter des noms |
|---|
| 1092 | pour la suite de l'exécution, peut-être pour référence dans une clause |
|---|
| 1093 | <literal>ORDER BY</literal> ou pour affichage par l'application cliente. |
|---|
| 1094 | Par exemple : |
|---|
| 1095 | <programlisting>SELECT a AS valeur, b + c AS sum FROM ...</programlisting> |
|---|
| 1096 | </para> |
|---|
| 1097 | |
|---|
| 1098 | <para> |
|---|
| 1099 | Si aucun nom de colonne en sortie n'est spécifié en utilisant |
|---|
| 1100 | <literal>AS</literal>, le système affecte un nom de colonne par défaut. |
|---|
| 1101 | Pour les références de colonne simple, c'est le nom de la colonne |
|---|
| 1102 | référencée. Pour les appels de fonction, il s'agit du nom de la fonction. |
|---|
| 1103 | Pour les expressions complexes, le système générera un nom générique. |
|---|
| 1104 | </para> |
|---|
| 1105 | |
|---|
| 1106 | <para> |
|---|
| 1107 | Le mot clé <literal>AS</literal> est optionnel, mais seulement si le |
|---|
| 1108 | nouveau nom de colonne ne correspond à aucun des mots clés |
|---|
| 1109 | <productname>PostgreSQL</productname> (voir <xref |
|---|
| 1110 | linkend="sql-keywords-appendix"/>). Pour éviter une correspondance |
|---|
| 1111 | accidentelle à un mot clé, vous pouvez mettre le nom de colonne entre |
|---|
| 1112 | guillemets. Par exemple, <literal>VALUE</literal> est un mot clé, ce qui |
|---|
| 1113 | fait que ceci ne fonctionne pas : |
|---|
| 1114 | <programlisting> |
|---|
| 1115 | SELECT a valeur, b + c AS somme FROM ... |
|---|
| 1116 | </programlisting> |
|---|
| 1117 | mais ceci fonctionne : |
|---|
| 1118 | <programlisting> |
|---|
| 1119 | SELECT a "valeur", b + c AS somme FROM ... |
|---|
| 1120 | </programlisting> |
|---|
| 1121 | Pour vous protéger de possibles ajouts futurs de mots clés, il est recommandé |
|---|
| 1122 | de toujours écrire <literal>AS</literal> ou de mettre le nom de colonne de |
|---|
| 1123 | sortie entre guillemets. |
|---|
| 1124 | </para> |
|---|
| 1125 | |
|---|
| 1126 | <note> |
|---|
| 1127 | <para> |
|---|
| 1128 | Le nom des colonnes en sortie est différent ici de ce qui est fait dans la |
|---|
| 1129 | clause <literal>FROM</literal> (voir la <xref linkend="queries-table-aliases"/>). |
|---|
| 1130 | Il est possible de renommer deux fois la même colonne mais le nom affecté |
|---|
| 1131 | dans la liste de sélection est celui qui sera passé. |
|---|
| 1132 | </para> |
|---|
| 1133 | </note> |
|---|
| 1134 | </sect2> |
|---|
| 1135 | |
|---|
| 1136 | <sect2 id="queries-distinct"> |
|---|
| 1137 | <title><literal>DISTINCT</literal></title> |
|---|
| 1138 | |
|---|
| 1139 | <indexterm zone="queries-distinct"> |
|---|
| 1140 | <primary>DISTINCT</primary> |
|---|
| 1141 | </indexterm> |
|---|
| 1142 | |
|---|
| 1143 | <indexterm zone="queries-distinct"> |
|---|
| 1144 | <primary>duplication</primary> |
|---|
| 1145 | </indexterm> |
|---|
| 1146 | |
|---|
| 1147 | <para> |
|---|
| 1148 | Après le traitement de la liste de sélection, la table résultant pourrait |
|---|
| 1149 | être optionnellement sujet à l'élimination des lignes dupliquées. Le mot clé |
|---|
| 1150 | <literal>DISTINCT</literal> est écrit directement après |
|---|
| 1151 | <literal>SELECT</literal> pour spécifier ceci : |
|---|
| 1152 | <synopsis>SELECT DISTINCT <replaceable>liste_selection</replaceable> ...</synopsis> |
|---|
| 1153 | (au lieu de <literal>DISTINCT</literal>, le mot clé <literal>ALL</literal> peut être |
|---|
| 1154 | utilisé pour spécifier le comportement par défaut, la récupération de |
|---|
| 1155 | toutes les lignes) |
|---|
| 1156 | </para> |
|---|
| 1157 | |
|---|
| 1158 | <para> |
|---|
| 1159 | <indexterm><primary>valeur NULL</primary><secondary sortas="DISTINCT">dans |
|---|
| 1160 | DISTINCT</secondary></indexterm> |
|---|
| 1161 | Évidemment, les deux lignes sont considérées distinctes si elles diffèrent |
|---|
| 1162 | dans au moins une valeur de colonne. Les valeurs NULL sont considérées |
|---|
| 1163 | égales dans cette comparaison. |
|---|
| 1164 | </para> |
|---|
| 1165 | |
|---|
| 1166 | <para> |
|---|
| 1167 | Autrement, une expression arbitraire peut déterminer quelles lignes |
|---|
| 1168 | doivent être considérées distinctes : |
|---|
| 1169 | <synopsis>SELECT DISTINCT ON (<replaceable>expression</replaceable> <optional>, <replaceable>expression</replaceable> ...</optional>) <replaceable>liste_selection</replaceable> ... </synopsis> |
|---|
| 1170 | Ici, <replaceable>expression</replaceable> est une expression de valeur |
|---|
| 1171 | arbitraire, évaluée pour toutes les lignes. Les lignes dont toutes les |
|---|
| 1172 | expressions sont égales sont considérées comme dupliquées et seule la |
|---|
| 1173 | première ligne de cet ensemble est conservée dans la sortie. Notez que la |
|---|
| 1174 | <quote>première ligne</quote> d'un ensemble est non prévisible sauf si la |
|---|
| 1175 | requête est triée sur assez de colonnes pour garantir un ordre unique des |
|---|
| 1176 | colonnes arrivant dans le filtre <literal>DISTINCT</literal> (le traitement de |
|---|
| 1177 | <literal>DISTINCT ON</literal> parvient après le tri de <literal>ORDER BY</literal>). |
|---|
| 1178 | </para> |
|---|
| 1179 | |
|---|
| 1180 | <para> |
|---|
| 1181 | La clause <literal>DISTINCT ON</literal> ne fait pas partie du standard SQL et est |
|---|
| 1182 | quelque fois considérée comme étant un mauvais style à cause de la nature |
|---|
| 1183 | potentiellement indéterminée de ses résultats. Avec l'utilisation judicieuse |
|---|
| 1184 | de <literal>GROUP BY</literal> et de sous-requêtes dans <literal>FROM</literal>, la |
|---|
| 1185 | construction peut être évitée mais elle représente souvent l'alternative la |
|---|
| 1186 | plus agréable. |
|---|
| 1187 | </para> |
|---|
| 1188 | </sect2> |
|---|
| 1189 | </sect1> |
|---|
| 1190 | |
|---|
| 1191 | |
|---|
| 1192 | <sect1 id="queries-union"> |
|---|
| 1193 | <title>Combiner des requêtes</title> |
|---|
| 1194 | |
|---|
| 1195 | <indexterm zone="queries-union"> |
|---|
| 1196 | <primary>UNION</primary> |
|---|
| 1197 | </indexterm> |
|---|
| 1198 | <indexterm zone="queries-union"> |
|---|
| 1199 | <primary>INTERSECT</primary> |
|---|
| 1200 | </indexterm> |
|---|
| 1201 | <indexterm zone="queries-union"> |
|---|
| 1202 | <primary>EXCEPT</primary> |
|---|
| 1203 | </indexterm> |
|---|
| 1204 | <indexterm zone="queries-union"> |
|---|
| 1205 | <primary>set union</primary> |
|---|
| 1206 | </indexterm> |
|---|
| 1207 | <indexterm zone="queries-union"> |
|---|
| 1208 | <primary>set intersection</primary> |
|---|
| 1209 | </indexterm> |
|---|
| 1210 | <indexterm zone="queries-union"> |
|---|
| 1211 | <primary>set difference</primary> |
|---|
| 1212 | </indexterm> |
|---|
| 1213 | <indexterm zone="queries-union"> |
|---|
| 1214 | <primary>set operation</primary> |
|---|
| 1215 | </indexterm> |
|---|
| 1216 | |
|---|
| 1217 | <para> |
|---|
| 1218 | Les résultats de deux requêtes peuvent être combinés en utilisant les |
|---|
| 1219 | opérations d'ensemble : union, intersection et différence. La syntaxe |
|---|
| 1220 | est |
|---|
| 1221 | <synopsis><replaceable>requete1</replaceable> UNION <optional>ALL</optional> <replaceable>requete2</replaceable> |
|---|
| 1222 | <replaceable>requete1</replaceable> INTERSECT <optional>ALL</optional> <replaceable>requete2</replaceable> |
|---|
| 1223 | <replaceable>requete1</replaceable> EXCEPT <optional>ALL</optional> <replaceable>requete2</replaceable></synopsis> |
|---|
| 1224 | <replaceable>requete1</replaceable> et |
|---|
| 1225 | <replaceable>requete2</replaceable> sont les requêtes pouvant utiliser |
|---|
| 1226 | toutes les fonctionnalités discutées ici. Les opérations d'ensemble peuvent |
|---|
| 1227 | aussi être combinées et chaînées, par exemple |
|---|
| 1228 | <synopsis><replaceable>requete1</replaceable> UNION <replaceable>requete2</replaceable> UNION <replaceable>requete3</replaceable></synopsis> |
|---|
| 1229 | est exécuté ainsi : |
|---|
| 1230 | <synopsis>(<replaceable>requete1</replaceable> UNION <replaceable>requete2</replaceable>) UNION <replaceable>requete3</replaceable></synopsis> |
|---|
| 1231 | </para> |
|---|
| 1232 | |
|---|
| 1233 | <para> |
|---|
| 1234 | <literal>UNION</literal> ajoute effectivement le résultat de |
|---|
| 1235 | <replaceable>requete2</replaceable> au résultat de |
|---|
| 1236 | <replaceable>requete1</replaceable> (bien qu'il n'y ait pas de garantie |
|---|
| 1237 | qu'il s'agit de l'ordre dans lequel les lignes sont réellement renvoyées). De |
|---|
| 1238 | plus, il élimine les lignes dupliquées du résultat, de la même façon que |
|---|
| 1239 | <literal>DISTINCT</literal>, sauf si <literal>UNION ALL</literal> est utilisée. |
|---|
| 1240 | </para> |
|---|
| 1241 | |
|---|
| 1242 | <para> |
|---|
| 1243 | <literal>INTERSECT</literal> renvoie toutes les lignes qui sont à la fois dans le |
|---|
| 1244 | résultat de <replaceable>requete1</replaceable> et dans le résultat de |
|---|
| 1245 | <replaceable>requete2</replaceable>. Les lignes dupliquées sont éliminées |
|---|
| 1246 | sauf si <literal>INTERSECT ALL</literal> est utilisé. |
|---|
| 1247 | </para> |
|---|
| 1248 | |
|---|
| 1249 | <para> |
|---|
| 1250 | <literal>EXCEPT</literal> renvoie toutes les lignes qui sont dans le résultat de |
|---|
| 1251 | <replaceable>requete1</replaceable> mais pas dans le résultat de |
|---|
| 1252 | <replaceable>requete2</replaceable> (ceci est quelque fois appelé la |
|---|
| 1253 | <firstterm>différence</firstterm> entre deux requêtes). De nouveau, les lignes |
|---|
| 1254 | dupliquées sont éliminées sauf si <literal>EXCEPT ALL</literal> est utilisé. |
|---|
| 1255 | </para> |
|---|
| 1256 | |
|---|
| 1257 | <para> |
|---|
| 1258 | Pour calculer l'union, l'intersection ou la différence de deux requêtes, les |
|---|
| 1259 | deux requêtes doivent être <quote>compatibles pour une union</quote>, ce qui |
|---|
| 1260 | signifie qu'elles doivent renvoyer le même nombre de colonnes et que les |
|---|
| 1261 | colonnes correspondantes doivent avoir des types de données compatibles, |
|---|
| 1262 | comme décrit dans la <xref linkend="typeconv-union-case"/>. |
|---|
| 1263 | </para> |
|---|
| 1264 | </sect1> |
|---|
| 1265 | |
|---|
| 1266 | |
|---|
| 1267 | <sect1 id="queries-order"> |
|---|
| 1268 | <title>Tri des lignes</title> |
|---|
| 1269 | |
|---|
| 1270 | <indexterm zone="queries-order"> |
|---|
| 1271 | <primary>tri</primary> |
|---|
| 1272 | </indexterm> |
|---|
| 1273 | |
|---|
| 1274 | <indexterm zone="queries-order"> |
|---|
| 1275 | <primary>ORDER BY</primary> |
|---|
| 1276 | </indexterm> |
|---|
| 1277 | |
|---|
| 1278 | <para> |
|---|
| 1279 | Après qu'une requête ait produit une table en sortie (après que la liste de |
|---|
| 1280 | sélection ait été traitée), elle peut être optionnellement triée. Si le tri |
|---|
| 1281 | n'a pas été choisi, les lignes sont renvoyées dans un ordre non spécifié. |
|---|
| 1282 | Dans ce cas, l'ordre réel dépendra des types de plan de parcours et de |
|---|
| 1283 | jointure et de l'ordre sur le disque mais vous ne devez pas vous y fier. Un |
|---|
| 1284 | tri particulier en sortie peut seulement être garantie si l'étape de tri est |
|---|
| 1285 | choisie explicitement. |
|---|
| 1286 | </para> |
|---|
| 1287 | |
|---|
| 1288 | <para> |
|---|
| 1289 | La clause <literal>ORDER BY</literal> spécifie l'ordre de tri : |
|---|
| 1290 | <synopsis>SELECT <replaceable>liste_selection</replaceable> |
|---|
| 1291 | FROM <replaceable>expression_table</replaceable> |
|---|
| 1292 | ORDER BY <replaceable>expression_tri1</replaceable> <optional>ASC | DESC</optional> <optional>NULLS { FIRST | LAST }</optional> |
|---|
| 1293 | <optional>, <replaceable>expression_tri2</replaceable> <optional>ASC | DESC</optional> <optional>NULLS { FIRST | LAST }</optional> ...</optional> |
|---|
| 1294 | </synopsis> |
|---|
| 1295 | |
|---|
| 1296 | Les expressions de tri peuvent être toute expression qui serait valide dans |
|---|
| 1297 | la liste de sélection des requêtes. Voici un exemple : |
|---|
| 1298 | <programlisting> |
|---|
| 1299 | SELECT a, b FROM table1 ORDER BY a + b, c; |
|---|
| 1300 | </programlisting> |
|---|
| 1301 | Quand plus d'une expression est indiquée, les valeurs suivantes sont |
|---|
| 1302 | utilisées pour trier les lignes qui sont identiques aux valeurs précédentes. |
|---|
| 1303 | Chaque expression pourrait être suivie d'un |
|---|
| 1304 | <literal>ASC</literal> ou <literal>DESC</literal> optionnel pour configurer la |
|---|
| 1305 | direction du tri (ascendant ou descendant). L'ordre <literal>ASC</literal> est la |
|---|
| 1306 | valeur par défaut. L'ordre ascendant place les plus petites valeurs en |
|---|
| 1307 | premier où <quote>plus petit</quote> est défini avec l'opérateur |
|---|
| 1308 | <literal><</literal>. De façon similaire, l'ordre descendant est |
|---|
| 1309 | déterminé avec l'opérateur <literal>></literal>. |
|---|
| 1310 | <footnote> |
|---|
| 1311 | <para> |
|---|
| 1312 | En fait, <productname>PostgreSQL</productname> utilise la <firstterm>classe |
|---|
| 1313 | d'opérateur B-tree par défaut</firstterm> pour le type de données de |
|---|
| 1314 | l'expression pour déterminer l'ordre de tri avec <literal>ASC</literal> |
|---|
| 1315 | et <literal>DESC</literal>. |
|---|
| 1316 | De façon conventionnelle, les types de données seront initialisés de |
|---|
| 1317 | façon à ce que les opérateurs <literal><</literal> et |
|---|
| 1318 | <literal>></literal> correspondent à cet ordre de tri mais un |
|---|
| 1319 | concepteur des types de données définis par l'utilisateur pourrait choisir |
|---|
| 1320 | de faire quelque chose de différent. |
|---|
| 1321 | </para> |
|---|
| 1322 | </footnote> |
|---|
| 1323 | </para> |
|---|
| 1324 | |
|---|
| 1325 | <para> |
|---|
| 1326 | Les options <literal>NULLS FIRST</literal> et <literal>NULLS LAST</literal> |
|---|
| 1327 | sont utilisées pour déterminer si les valeurs NULL apparaissent avant ou |
|---|
| 1328 | après les valeurs non NULL après un tri. Par défaut, les valeurs NULL sont |
|---|
| 1329 | triées comme si elles étaient plus grandes que toute valeur non NULL. |
|---|
| 1330 | Autrement dit, <literal>NULLS FIRST</literal> est la valeur par défaut pour |
|---|
| 1331 | l'ordre descendant (<literal>DESC</literal>) et <literal>NULLS LAST</literal> |
|---|
| 1332 | est la valeur utilisée sinon. |
|---|
| 1333 | </para> |
|---|
| 1334 | |
|---|
| 1335 | <para> |
|---|
| 1336 | Notez que les options de tri sont considérées indépendament pour chaque |
|---|
| 1337 | colonne triée. Par exemple, <literal>ORDER BY x, y DESC</literal> signifie |
|---|
| 1338 | en fait <literal>ORDER BY x ASC, y DESC</literal>, ce qui est différent de |
|---|
| 1339 | <literal>ORDER BY x DESC, y DESC</literal>. |
|---|
| 1340 | </para> |
|---|
| 1341 | |
|---|
| 1342 | <para> |
|---|
| 1343 | Une <replaceable>expression_tri</replaceable> peut aussi être à la place |
|---|
| 1344 | le nom ou le numéro d'une colonne en sortie, par exemple : |
|---|
| 1345 | <programlisting>SELECT a + b AS sum, c FROM table1 ORDER BY sum; |
|---|
| 1346 | SELECT a, max(b) FROM table1 GROUP BY a ORDER BY 1; |
|---|
| 1347 | </programlisting> |
|---|
| 1348 | les deux triant par la première colonne en sortie. Notez qu'un nom de colonne |
|---|
| 1349 | en sortie doit être unique, il ne doit pas être utilisé dans une expression |
|---|
| 1350 | — par exemple, ceci n'est <emphasis>pas</emphasis> correct : |
|---|
| 1351 | <programlisting> |
|---|
| 1352 | SELECT a + b AS sum, c FROM table1 ORDER BY sum + c; -- mauvais |
|---|
| 1353 | </programlisting> |
|---|
| 1354 | Cette restriction est là pour réduire l'ambiguïté. Il y en a toujours si un |
|---|
| 1355 | élément <literal>ORDER BY</literal> est un simple nom qui pourrait |
|---|
| 1356 | correspondre soit à un nom de colonne en sortie soit à une colonne d'une |
|---|
| 1357 | expression de table. La colonne en sortie est utilisée dans de tels cas. |
|---|
| 1358 | Cela causera seulement de la confusion si vous utilisez <literal>AS</literal> |
|---|
| 1359 | pour renommer une colonne en sortie qui correspondra à un autre nom de |
|---|
| 1360 | colonne d'une table. |
|---|
| 1361 | </para> |
|---|
| 1362 | |
|---|
| 1363 | <para> |
|---|
| 1364 | <literal>ORDER BY</literal> peut être appliqué au résultat d'une combinaison |
|---|
| 1365 | <literal>UNION</literal>, d'une combinaison<literal>INTERSECT</literal> ou |
|---|
| 1366 | d'une combinaison <literal>EXCEPT</literal> mais, dans ce cas, il est |
|---|
| 1367 | seulement permis de trier par les noms ou numéros de colonnes, pas par les |
|---|
| 1368 | expressions. |
|---|
| 1369 | </para> |
|---|
| 1370 | </sect1> |
|---|
| 1371 | |
|---|
| 1372 | |
|---|
| 1373 | <sect1 id="queries-limit"> |
|---|
| 1374 | <title><literal>LIMIT</literal> et <literal>OFFSET</literal></title> |
|---|
| 1375 | |
|---|
| 1376 | <indexterm zone="queries-limit"> |
|---|
| 1377 | <primary>LIMIT</primary> |
|---|
| 1378 | </indexterm> |
|---|
| 1379 | |
|---|
| 1380 | <indexterm zone="queries-limit"> |
|---|
| 1381 | <primary>OFFSET</primary> |
|---|
| 1382 | </indexterm> |
|---|
| 1383 | |
|---|
| 1384 | <para> |
|---|
| 1385 | <literal>LIMIT</literal> et <literal>OFFSET</literal> vous permet de retrouver seulement |
|---|
| 1386 | une portion des lignes générées par le reste de la requête : |
|---|
| 1387 | <synopsis>SELECT <replaceable>liste_selection</replaceable> |
|---|
| 1388 | FROM <replaceable>expression_table</replaceable> |
|---|
| 1389 | <optional> ORDER BY ...</optional> |
|---|
| 1390 | <optional> LIMIT { <replaceable>nombre</replaceable> | ALL } </optional> <optional>OFFSET <replaceable>nombre</replaceable></optional></synopsis> |
|---|
| 1391 | </para> |
|---|
| 1392 | |
|---|
| 1393 | <para> |
|---|
| 1394 | Si un nombre limite est donné, pas plus que ce nombre de lignes sera renvoyé |
|---|
| 1395 | (mais peut-être moins si la requête récupère moins de lignes). <literal>LIMIT |
|---|
| 1396 | ALL</literal> revient à ne pas spécifier la clause <literal>LIMIT</literal>. |
|---|
| 1397 | </para> |
|---|
| 1398 | |
|---|
| 1399 | <para> |
|---|
| 1400 | <literal>OFFSET</literal> indique de passer ce nombre de lignes avant de renvoyer |
|---|
| 1401 | les lignes restantes. <literal>OFFSET 0</literal> revient à oublier la clause |
|---|
| 1402 | <literal>OFFSET</literal>, et <literal>LIMIT NULL</literal> revient à oublier |
|---|
| 1403 | la clause <literal>LIMIT</literal>. Si à la fois <literal>OFFSET</literal> et <literal>LIMIT</literal> |
|---|
| 1404 | apparaissent, alors les <literal>OFFSET</literal> lignes sont laissées avant de |
|---|
| 1405 | commencer le renvoi des <literal>LIMIT</literal> lignes. |
|---|
| 1406 | </para> |
|---|
| 1407 | |
|---|
| 1408 | <para> |
|---|
| 1409 | Lors de l'utilisation de <literal>LIMIT</literal>, il est important d'utiliser une |
|---|
| 1410 | clause <literal>ORDER BY</literal> contraignant les lignes résultantes dans un ordre |
|---|
| 1411 | unique. Sinon, vous obtiendrez un sous-ensemble non prévisible de lignes de |
|---|
| 1412 | la requête. Vous pourriez demander les lignes de 10 à 20 mais dans quel |
|---|
| 1413 | ordre ? L'ordre est inconnu si vous ne spécifiez pas <literal>ORDER |
|---|
| 1414 | BY</literal>. |
|---|
| 1415 | </para> |
|---|
| 1416 | |
|---|
| 1417 | <para> |
|---|
| 1418 | L'optimiseur de requêtes prend <literal>LIMIT</literal> en compte lors de la |
|---|
| 1419 | génération des plans de requêtes, de façon à ce que vous obteniez |
|---|
| 1420 | différents plans (avec différents ordres de lignes) suivant ce que vous |
|---|
| 1421 | donnez à <literal>LIMIT</literal> et <literal>OFFSET</literal>. Du coup, utiliser des |
|---|
| 1422 | valeurs <literal>LIMIT</literal>/<literal>OFFSET</literal> différentes pour sélectionner |
|---|
| 1423 | des sous-ensembles différents d'un résultat de requête <emphasis>donnera des |
|---|
| 1424 | résultats inconsistants</emphasis> sauf si vous forcez un ordre de |
|---|
| 1425 | résultat prévisible avec <literal>ORDER BY</literal>. Ceci n'est pas un bogue ; |
|---|
| 1426 | c'est une conséquence inhérente du fait que le SQL ne promette par de |
|---|
| 1427 | délivrer les résultats d'une requête dans un ordre particulier sauf si |
|---|
| 1428 | <literal>ORDER BY</literal> est utilisé pour contraindre l'ordre. |
|---|
| 1429 | </para> |
|---|
| 1430 | |
|---|
| 1431 | <para> |
|---|
| 1432 | Les lignes passées par une clause <literal>OFFSET</literal> devront toujours être |
|---|
| 1433 | traitées à l'intérieur du serveur ; du coup, un <literal>OFFSET</literal> |
|---|
| 1434 | important peut être inefficace. |
|---|
| 1435 | </para> |
|---|
| 1436 | </sect1> |
|---|
| 1437 | |
|---|
| 1438 | |
|---|
| 1439 | <sect1 id="queries-values"> |
|---|
| 1440 | <title>Listes <literal>VALUES</literal></title> |
|---|
| 1441 | |
|---|
| 1442 | <indexterm zone="queries-values"> |
|---|
| 1443 | <primary>VALUES</primary> |
|---|
| 1444 | </indexterm> |
|---|
| 1445 | |
|---|
| 1446 | <para> |
|---|
| 1447 | <literal>VALUES</literal> fournit une façon de générer une table de |
|---|
| 1448 | <quote>constantes</quote> qui peut être utilisé dans une requête sans |
|---|
| 1449 | avoir à réellement créer et peupler une table sur disque. La syntaxe est |
|---|
| 1450 | <synopsis> |
|---|
| 1451 | VALUES ( <replaceable class="parameter">expression</replaceable> [, ...] ) [, ...] |
|---|
| 1452 | </synopsis> |
|---|
| 1453 | Chaque liste d'expressions entre parenthèses génère une ligne dans la table. |
|---|
| 1454 | Les listes doivent toutes avoir le même nombre d'éléments (c'est-à-dire une |
|---|
| 1455 | liste de colonnes dans la table), et les entrées correspondantes dans chaque |
|---|
| 1456 | liste doivent avoir des types compatibles. Le type réel affecté à chaque colonne |
|---|
| 1457 | du résultat est déterminé en utilisant les mêmes règles que pour |
|---|
| 1458 | <literal>UNION</literal> (voir <xref linkend="typeconv-union-case"/>). |
|---|
| 1459 | </para> |
|---|
| 1460 | |
|---|
| 1461 | <para> |
|---|
| 1462 | Voici un exemple : |
|---|
| 1463 | |
|---|
| 1464 | <programlisting>VALUES (1, 'un'), (2, 'deux'), (3, 'trois'); |
|---|
| 1465 | </programlisting> |
|---|
| 1466 | |
|---|
| 1467 | renverra une table de deux colonnes et trois lignes. C'est équivalent à : |
|---|
| 1468 | |
|---|
| 1469 | <programlisting>SELECT 1 AS column1, 'un' AS column2 |
|---|
| 1470 | UNION ALL |
|---|
| 1471 | SELECT 2, 'deux' |
|---|
| 1472 | UNION ALL |
|---|
| 1473 | SELECT 3, 'trois'; |
|---|
| 1474 | </programlisting> |
|---|
| 1475 | |
|---|
| 1476 | Par défaut, <productname>PostgreSQL</productname> affecte les noms |
|---|
| 1477 | <literal>column1</literal>, <literal>column2</literal>, etc. aux colonnes |
|---|
| 1478 | d'une table <literal>VALUES</literal>. Les noms des colonnes ne sont pas |
|---|
| 1479 | spécifiés par le standard SQL et les différents SGBD le font de façon |
|---|
| 1480 | différente. Donc, il est généralement mieux de surcharger les noms par |
|---|
| 1481 | défaut avec une liste d'alias. |
|---|
| 1482 | </para> |
|---|
| 1483 | |
|---|
| 1484 | <para> |
|---|
| 1485 | Syntaxiquement, <literal>VALUES</literal> suivi par une liste d'expressions |
|---|
| 1486 | est traité de la même façon que |
|---|
| 1487 | <synopsis>SELECT <replaceable>liste_select</replaceable> FROM <replaceable>expression_table</replaceable> |
|---|
| 1488 | </synopsis> |
|---|
| 1489 | et peut apparaître partout où un <literal>SELECT</literal> le peut. Par |
|---|
| 1490 | exemple, vous pouvez l'utiliser comme élément d'un <literal>UNION</literal> |
|---|
| 1491 | ou y attacher une <replaceable>spécification de tri</replaceable> |
|---|
| 1492 | (<literal>ORDER BY</literal>, <literal>LIMIT</literal> et/ou <literal>OFFSET</literal>). |
|---|
| 1493 | <literal>VALUES</literal> est habituellement utilisée comme source de données |
|---|
| 1494 | dans une commande <command>INSERT</command> command, mais aussi dans une |
|---|
| 1495 | sous-requête. |
|---|
| 1496 | </para> |
|---|
| 1497 | |
|---|
| 1498 | <para> |
|---|
| 1499 | Pour plus d'informations, voir <xref linkend="sql-values" |
|---|
| 1500 | endterm="sql-values-title"/>. |
|---|
| 1501 | </para> |
|---|
| 1502 | |
|---|
| 1503 | </sect1> |
|---|
| 1504 | |
|---|
| 1505 | |
|---|
| 1506 | <sect1 id="queries-with"> |
|---|
| 1507 | <title>Requêtes <literal>WITH</literal></title> |
|---|
| 1508 | |
|---|
| 1509 | <indexterm zone="queries-with"> |
|---|
| 1510 | <primary>WITH</primary> |
|---|
| 1511 | <secondary>dans SELECT</secondary> |
|---|
| 1512 | </indexterm> |
|---|
| 1513 | |
|---|
| 1514 | <indexterm> |
|---|
| 1515 | <primary>common table expression</primary> |
|---|
| 1516 | <see>WITH</see> |
|---|
| 1517 | </indexterm> |
|---|
| 1518 | |
|---|
| 1519 | <para> |
|---|
| 1520 | <literal>WITH</literal> fournit une façon d'écrire les sous-requêtes pour |
|---|
| 1521 | utilisation dans une requête <literal>SELECT</literal> plus étendue. Les |
|---|
| 1522 | sous-requêtes peuvent être considérées comme la déclaration d'une table |
|---|
| 1523 | temporaire n'existant que pour la requête. Une utilisation de cette |
|---|
| 1524 | fonctionnalité est de découper des requêtes complexes en parties plus simples. |
|---|
| 1525 | En voici un exemple : |
|---|
| 1526 | |
|---|
| 1527 | <programlisting>WITH ventes_regionales AS ( |
|---|
| 1528 | SELECT region, SUM(montant) AS ventes_totales |
|---|
| 1529 | FROM commandes |
|---|
| 1530 | GROUP BY region |
|---|
| 1531 | ), meilleures_regions AS ( |
|---|
| 1532 | SELECT region |
|---|
| 1533 | FROM ventes_regionales |
|---|
| 1534 | WHERE ventes_totales > (SELECT SUM(ventes_totales)/10 FROM ventes_regionales) |
|---|
| 1535 | ) |
|---|
| 1536 | SELECT region, |
|---|
| 1537 | produit, |
|---|
| 1538 | SUM(quantite) AS unites_produit, |
|---|
| 1539 | SUM(montant) AS ventes_produit |
|---|
| 1540 | FROM commandes |
|---|
| 1541 | WHERE region IN (SELECT region FROM meilleures_regions) |
|---|
| 1542 | GROUP BY region, produit;</programlisting> |
|---|
| 1543 | |
|---|
| 1544 | qui affiche les totaux de ventes par produit dans seulement les régions |
|---|
| 1545 | ayant les meilleures ventes. Cet exemple aurait pu être écrit sans |
|---|
| 1546 | <literal>WITH</literal>, mais aurait alors nécessité deux niveaux de |
|---|
| 1547 | sous-SELECT imbriqués. Les choses sont un peu plus faciles à suivre de cette |
|---|
| 1548 | façon. |
|---|
| 1549 | </para> |
|---|
| 1550 | |
|---|
| 1551 | <para> |
|---|
| 1552 | Le modificateur optionnel <literal>RECURSIVE</literal> fait passer |
|---|
| 1553 | <literal>WITH</literal> du statut de simple aide syntaxique à celui de |
|---|
| 1554 | quelque chose qu'il serait impossible d'accomplir avec du SQL standard. |
|---|
| 1555 | Grâce à <literal>RECURSIVE</literal>, une requête <literal>WITH</literal> |
|---|
| 1556 | peut utiliser sa propre sortie. Un exemple très simple se trouve dans cette |
|---|
| 1557 | requête, qui ajoute les nombres de 1 à 100 : |
|---|
| 1558 | |
|---|
| 1559 | <programlisting>WITH RECURSIVE t(n) AS ( |
|---|
| 1560 | VALUES (1) |
|---|
| 1561 | UNION ALL |
|---|
| 1562 | SELECT n+1 FROM t WHERE n < 100 |
|---|
| 1563 | ) |
|---|
| 1564 | SELECT sum(n) FROM t;</programlisting> |
|---|
| 1565 | |
|---|
| 1566 | La forme générale d'une requête <literal>WITH</literal> est toujours un |
|---|
| 1567 | <firstterm>terme non-recursif</firstterm>, puis <literal>UNION</literal> (ou |
|---|
| 1568 | <literal>UNION ALL</literal>), puis un <firstterm>terme récursif</firstterm>. |
|---|
| 1569 | Seul le terme récursif peut contenir une référence à la sortie propre de la |
|---|
| 1570 | requête. Une requête de ce genre est exécutée comme suit : |
|---|
| 1571 | </para> |
|---|
| 1572 | |
|---|
| 1573 | <procedure> |
|---|
| 1574 | <title>Évaluation de requête récursive</title> |
|---|
| 1575 | |
|---|
| 1576 | <step performance="required"> |
|---|
| 1577 | <para> |
|---|
| 1578 | Évaluer le terme non récursif. Pour <literal>UNION</literal> (mais pas |
|---|
| 1579 | <literal>UNION ALL</literal>), supprimer les enregistrements en double. |
|---|
| 1580 | Inclure le reste dans le résultat de la requête récursive et le mettre |
|---|
| 1581 | aussi dans une table temporaire de travail (<firstterm>working table</firstterm>.) |
|---|
| 1582 | </para> |
|---|
| 1583 | </step> |
|---|
| 1584 | |
|---|
| 1585 | <step performance="required"> |
|---|
| 1586 | <para> |
|---|
| 1587 | Tant que la table de travail n'est pas vide, répéter ces étapes : |
|---|
| 1588 | </para> |
|---|
| 1589 | <substeps> |
|---|
| 1590 | <step performance="required"> |
|---|
| 1591 | <para> |
|---|
| 1592 | Évaluer le terme récursif, en substituant à la référence récursive |
|---|
| 1593 | le contenu courant de la table de travail. |
|---|
| 1594 | Pour <literal>UNION</literal> (mais pas <literal>UNION ALL</literal>), |
|---|
| 1595 | supprimer les doublons, ainsi que les enregistrements en doublon des |
|---|
| 1596 | enregistrements déjà obtenus. Inclure les enregistrements restants dans |
|---|
| 1597 | le résultat de la requête récursive, et les mettre aussi dans une table |
|---|
| 1598 | temporaire intermédiaire (<firstterm>intermediate table</firstterm>). |
|---|
| 1599 | </para> |
|---|
| 1600 | </step> |
|---|
| 1601 | |
|---|
| 1602 | <step performance="required"> |
|---|
| 1603 | <para> |
|---|
| 1604 | Remplacer le contenu de la table de travail par celui de la table |
|---|
| 1605 | intermédiaire, puis supprimer la table intermédiaire. |
|---|
| 1606 | </para> |
|---|
| 1607 | </step> |
|---|
| 1608 | </substeps> |
|---|
| 1609 | </step> |
|---|
| 1610 | </procedure> |
|---|
| 1611 | |
|---|
| 1612 | <note> |
|---|
| 1613 | <para> |
|---|
| 1614 | Dans son appellation stricte, ce processus est une itération, pas une |
|---|
| 1615 | récursion, mais <literal>RECURSIVE</literal> est la terminologie choisie |
|---|
| 1616 | par le comité de standardisation de SQL. |
|---|
| 1617 | </para> |
|---|
| 1618 | </note> |
|---|
| 1619 | |
|---|
| 1620 | <para> |
|---|
| 1621 | Dans l'exemple précédent, la table de travail a un seul enregistrement à |
|---|
| 1622 | chaque étape, et il prend les valeurs de 1 à 100 en étapes successives. |
|---|
| 1623 | À la centième étape, il n'y a plus de sortie en raison de la clause |
|---|
| 1624 | <literal>WHERE</literal>, ce qui met fin à la requête. |
|---|
| 1625 | </para> |
|---|
| 1626 | |
|---|
| 1627 | <para> |
|---|
| 1628 | Les requêtes récursives sont utilisées généralement pour traiter des données |
|---|
| 1629 | hiérarchiques ou sous forme d'arbres. Cette requête est un exemple utile |
|---|
| 1630 | pour trouver toutes les sous-parties directes et indirectes d'un produit, |
|---|
| 1631 | si seule une table donne toutes les inclusions immédiates : |
|---|
| 1632 | |
|---|
| 1633 | <programlisting>WITH RECURSIVE parties_incluses(sous_partie, partie, quantite) AS ( |
|---|
| 1634 | SELECT sous_partie, partie, quantite FROM parties WHERE partie = 'notre_produit' |
|---|
| 1635 | UNION ALL |
|---|
| 1636 | SELECT p.sous_partie, p.partie, p.quantite |
|---|
| 1637 | FROM parties_incluses pr, parties p |
|---|
| 1638 | WHERE p.partie = pr.sous_partie |
|---|
| 1639 | ) |
|---|
| 1640 | SELECT sous_partie, SUM(quantite) as quantite_totale |
|---|
| 1641 | FROM parties_incluses |
|---|
| 1642 | GROUP BY sous_partie</programlisting> |
|---|
| 1643 | </para> |
|---|
| 1644 | |
|---|
| 1645 | <para> |
|---|
| 1646 | Quand on travaille avec des requêtes récursives, il est important d'être sûr |
|---|
| 1647 | que la partie récursive de la requête finira par ne retourner aucun enregistrement, |
|---|
| 1648 | au risque sinon de voir la requête boucler indéfiniment. Quelquefois, utiliser |
|---|
| 1649 | <literal>UNION</literal> à la place de <literal>UNION ALL</literal> peut |
|---|
| 1650 | résoudre le problème en supprimant les enregistrements qui doublonnent ceux déjà |
|---|
| 1651 | retournés. Toutefois, souvent, un cycle ne met pas en jeu des enregistrements de |
|---|
| 1652 | sortie qui sont totalement des doublons : il peut s'avérer nécessaire de |
|---|
| 1653 | vérifier juste un ou quelques champs, afin de s'assurer que le même point a déjà |
|---|
| 1654 | été atteint précédemment. La méthode standard pour gérer ces situations est de |
|---|
| 1655 | calculer un tableau de valeurs déjà visitées. Par exemple, observez la requête |
|---|
| 1656 | suivante, qui parcourt une table <structname>graphe</structname> en utilisant |
|---|
| 1657 | un champ <structfield>lien</structfield> : |
|---|
| 1658 | |
|---|
| 1659 | <programlisting> |
|---|
| 1660 | WITH RECURSIVE parcourt_graphe(id, lien, donnee, profondeur) AS ( |
|---|
| 1661 | SELECT g.id, g.lien, g.donnee, 1 |
|---|
| 1662 | FROM graphe g |
|---|
| 1663 | UNION ALL |
|---|
| 1664 | SELECT g.id, g.lien, g.donnee, sg.profondeur + 1 |
|---|
| 1665 | FROM graphe g, parcourt_graphe sg |
|---|
| 1666 | WHERE g.id = sg.lien |
|---|
| 1667 | ) |
|---|
| 1668 | SELECT * FROM parcourt_graphe; |
|---|
| 1669 | </programlisting> |
|---|
| 1670 | |
|---|
| 1671 | Cette requête va boucler si la liaison <structfield>lien</structfield> |
|---|
| 1672 | contient des boucles. Parce que nous avons besoin de la sortie |
|---|
| 1673 | <quote>profondeur</quote>, simplement remplacer <literal>UNION ALL</literal> |
|---|
| 1674 | par <literal>UNION</literal> ne résoudra pas le problème. |
|---|
| 1675 | À la place, nous avons besoin d'identifier si nous avons atteint un enregistrement |
|---|
| 1676 | que nous avons déjà traité pendant notre parcours des liens. Nous ajoutons |
|---|
| 1677 | deux colonnes <structfield>chemin</structfield> et <structfield>boucle</structfield> |
|---|
| 1678 | à la requête : |
|---|
| 1679 | <programlisting> |
|---|
| 1680 | WITH RECURSIVE parcourt_graphe(id, lien, donnee, profondeur, chemin, boucle) AS ( |
|---|
| 1681 | SELECT g.id, g.lien, g.donnee, 1, |
|---|
| 1682 | ARRAY[g.id], |
|---|
| 1683 | false |
|---|
| 1684 | FROM graphe g |
|---|
| 1685 | UNION ALL |
|---|
| 1686 | SELECT g.id, g.lien, g.donnee, sg.profondeur + 1, |
|---|
| 1687 | chemin || g.id, |
|---|
| 1688 | g.id = ANY(chemin) |
|---|
| 1689 | FROM graphe g, parcourt_graphe sg |
|---|
| 1690 | WHERE g.id = sg.lien AND NOT boucle |
|---|
| 1691 | ) |
|---|
| 1692 | SELECT * FROM parcourt_graphe; |
|---|
| 1693 | </programlisting> |
|---|
| 1694 | |
|---|
| 1695 | En plus de prévenir les boucles, cette valeur de tableau est souvent pratique |
|---|
| 1696 | en elle-même pour représenter le <quote>chemin</quote> pris pour atteindre |
|---|
| 1697 | chaque enregistrement. |
|---|
| 1698 | </para> |
|---|
| 1699 | |
|---|
| 1700 | <para> |
|---|
| 1701 | De façon plus générale, quand plus d'un champ a besoin d'être vérifié pour |
|---|
| 1702 | identifier une boucle, utilisez un tableau d'enregistrements. Par exemple, |
|---|
| 1703 | si nous avions besoin de comparer les champs <structfield>f1</structfield> et |
|---|
| 1704 | <structfield>f2</structfield> : |
|---|
| 1705 | |
|---|
| 1706 | <programlisting> |
|---|
| 1707 | WITH RECURSIVE parcourt_graphe(id, lien, donnee, profondeur, chemin, boucle) AS ( |
|---|
| 1708 | SELECT g.id, g.lien, g.donnee, 1, |
|---|
| 1709 | ARRAY[ROW(g.f1, g.f2)], |
|---|
| 1710 | false |
|---|
| 1711 | FROM graphe g |
|---|
| 1712 | UNION ALL |
|---|
| 1713 | SELECT g.id, g.lien, g.donnee, sg.profondeur + 1, |
|---|
| 1714 | chemin || ROW(g.f1, g.f2), |
|---|
| 1715 | ROW(g.f1, g.f2) = ANY(path) |
|---|
| 1716 | FROM graphe g, parcourt_graphe sg |
|---|
| 1717 | WHERE g.id = sg.link AND NOT boucle |
|---|
| 1718 | ) |
|---|
| 1719 | SELECT * FROM parcourt_graphe; |
|---|
| 1720 | </programlisting> |
|---|
| 1721 | </para> |
|---|
| 1722 | |
|---|
| 1723 | <tip> |
|---|
| 1724 | <para> |
|---|
| 1725 | Omettez la syntaxe <literal>ROW()</literal> dans le cas courant où un seul |
|---|
| 1726 | champ a besoin d'être testé pour déterminer une boucle. Ceci permet, par |
|---|
| 1727 | l'utilisation d'un tableau simple plutôt que d'un tableau de type composite, |
|---|
| 1728 | de gagner en efficacité. |
|---|
| 1729 | </para> |
|---|
| 1730 | </tip> |
|---|
| 1731 | |
|---|
| 1732 | <tip> |
|---|
| 1733 | <para> |
|---|
| 1734 | L'algorithme d'évaluation récursive de requête produit sa sortie en ordre |
|---|
| 1735 | de parcours en largeur (algorithme <foreignphrase>breadth-first</foreignphrase>). |
|---|
| 1736 | Vous pouvez afficher les résultats en ordre de parcours en profondeur |
|---|
| 1737 | (<foreignphrase>depth-first</foreignphrase>) en faisant sur la requête |
|---|
| 1738 | externe un <literal>ORDER BY</literal> sur une colonne <quote>chemin</quote> |
|---|
| 1739 | construite de cette façon. |
|---|
| 1740 | </para> |
|---|
| 1741 | </tip> |
|---|
| 1742 | |
|---|
| 1743 | <para> |
|---|
| 1744 | Si vous n'êtes pas certain qu'une requête peut boucler, une astuce pratique |
|---|
| 1745 | pour la tester est d'utiliser <literal>LIMIT</literal> dans la requête parente. |
|---|
| 1746 | Par exemple, cette requête bouclerait indéfiniment sans un |
|---|
| 1747 | <literal>LIMIT</literal> : |
|---|
| 1748 | |
|---|
| 1749 | <programlisting> |
|---|
| 1750 | WITH RECURSIVE t(n) AS ( |
|---|
| 1751 | SELECT 1 |
|---|
| 1752 | UNION ALL |
|---|
| 1753 | SELECT n+1 FROM t |
|---|
| 1754 | ) |
|---|
| 1755 | SELECT n FROM t LIMIT 100; |
|---|
| 1756 | </programlisting> |
|---|
| 1757 | |
|---|
| 1758 | Ceci fonctionne parce que l'implémentation de <productname>PostgreSQL</productname> |
|---|
| 1759 | n'évalue que le nombre d'enregistrements de la requête <literal>WITH</literal> |
|---|
| 1760 | récupérés par la requête parente. L'utilisation de cette astuce en production |
|---|
| 1761 | est déconseillée parce que d'autres systèmes pourraient fonctionner différemment. |
|---|
| 1762 | Par ailleurs, cela ne fonctionnera pas si vous demandez à la requête externe |
|---|
| 1763 | de trier les résultats de la requête récursive, ou si vous les joignez à une |
|---|
| 1764 | autre table. |
|---|
| 1765 | </para> |
|---|
| 1766 | |
|---|
| 1767 | <para> |
|---|
| 1768 | Une propriété intéressante des requêtes <literal>WITH</literal> est qu'elles |
|---|
| 1769 | ne sont évaluées qu'une seule fois par exécution de la requête parente ou |
|---|
| 1770 | des requêtes <literal>WITH</literal> sœurs. |
|---|
| 1771 | Par conséquent, les calculs coûteux qui sont nécessaires à plusieurs endroits |
|---|
| 1772 | peuvent être placés dans une requête <literal>WITH</literal> pour éviter le |
|---|
| 1773 | travail redondant. Un autre intérêt peut être d'éviter l'exécution multiple |
|---|
| 1774 | d'une fonction ayant des effets de bord. |
|---|
| 1775 | Toutefois, le revers de la médaille est que l'optimiseur est moins capable |
|---|
| 1776 | d'extrapoler les restrictions de la requête parente vers une requête |
|---|
| 1777 | <literal>WITH</literal> que vers une sous-requête classique. La requête |
|---|
| 1778 | <literal>WITH</literal> sera généralement exécutée telle quelle, sans |
|---|
| 1779 | suppression d'enregistrements, que la requête parente devra supprimer ensuite. |
|---|
| 1780 | (Mais, comme mentionné précédemment, l'évaluation pourrait s'arrêter rapidement |
|---|
| 1781 | si la (les) référence(s) à la requête ne demande(nt) qu'un nombre limité |
|---|
| 1782 | d'enregistrements). |
|---|
| 1783 | </para> |
|---|
| 1784 | |
|---|
| 1785 | </sect1> |
|---|
| 1786 | |
|---|
| 1787 | </chapter> |
|---|