forked from gleu/pgdocs_fr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
queries.xml
1404 lines (1214 loc) · 58.1 KB
/
queries.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="UTF-8"?>
<!-- Dernière modification
le $Date$
par $Author$
révision $Revision$ -->
<chapter id="queries">
<title>Requêtes</title>
<indexterm zone="queries">
<primary>requête</primary>
</indexterm>
<indexterm zone="queries">
<primary>SELECT</primary>
</indexterm>
<para>
Les précédents chapitres ont expliqué comme créer des tables, comment
les remplir avec des données et comment manipuler ces données.
Maintenant, nous discutons enfin de la façon de récupérer ces données
depuis la base de données.
</para>
<sect1 id="queries-overview">
<title>Aperçu</title>
<para>
Le processus et la commande de récupération des données sont appelés une
<firstterm>requête</firstterm>. En SQL, la commande <xref linkend="sql-select"
endterm="sql-select-title"/> est utilisée pour spécifier des requêtes. La
syntaxe générale de la commande <command>SELECT</command> est
<synopsis>SELECT <replaceable>liste_select</replaceable> FROM <replaceable>expression_table</replaceable> <optional><replaceable>specification_tri</replaceable></optional></synopsis>
Les sections suivantes décrivent le détail de la liste de sélection,
l'expression des tables et la spécification du tri.
</para>
<para>
Un type de requête simple est de la forme :
<programlisting>SELECT * FROM table1;</programlisting>
En supposant qu'il existe une table appelée <literal>table1</literal>, cette
commande récupérera toutes les lignes et toutes les colonnes de
<literal>table1</literal>. La méthode de récupération dépend de l'application
cliente. Par exemple, le programme <application>psql</application> affichera
une table, façon art ASCII, alors que les bibliothèques du client offriront
des fonctions d'extraction de valeurs individuelles à partir du résultat de
la requête. <literal>*</literal> comme liste de sélection signifie que toutes
les colonnes de l'expression de table seront récupérées. Une liste de sélection
peut aussi être un sous-ensemble des colonnes disponibles ou effectuer
un calcul en utilisant les colonnes. Par exemple, si <literal>table1</literal>
dispose des colonnes nommées <literal>a</literal>, <literal>b</literal> et <literal>c</literal> (et
peut-être d'autres), vous pouvez lancer la requête suivante :
<programlisting>SELECT a, b + c FROM table1;</programlisting>
(en supposant que <literal>b</literal> et <literal>c</literal> soient de type numérique).
Voir la <xref linkend="queries-select-lists"/> pour plus de détails.
</para>
<para>
<literal>FROM table1</literal> est un type très simple d'expression de
tables : il lit une seule table. En général, les expressions de tables
sont des constructions complexes de tables de base, de jointures et de
sous-requêtes. Mais vous pouvez aussi entièrement omettre l'expression de table
et utiliser la commande <command>SELECT</command> comme une calculatrice :
<programlisting>SELECT 3 * 4;</programlisting>
Ceci est plus utile si les expressions de la liste de sélection renvoient des
résultats variants. Par exemple, vous pouvez appeler une fonction de cette
façon :
<programlisting>SELECT random();</programlisting>
</para>
</sect1>
<sect1 id="queries-table-expressions">
<title>Expressions de table</title>
<indexterm zone="queries-table-expressions">
<primary>expression de table</primary>
</indexterm>
<para>
Une <firstterm>expression de table</firstterm> calcule une table.
L'expression de table contient une clause <literal>FROM</literal> qui peut être
suivie des clauses <literal>WHERE</literal>, <literal>GROUP BY</literal> et
<literal>HAVING</literal>. Les expressions triviales de table font simplement
référence à une table sur le disque, une table de base, mais des expressions
plus complexes peuvent être utilisées pour modifier ou combiner des tables
de base de différentes façons.
</para>
<para>
Les clauses optionnelles <literal>WHERE</literal>, <literal>GROUP BY</literal> et
<literal>HAVING</literal> dans l'expression de table spécifient un tube de
transformations successives réalisées sur la table dérivée de la
clause <literal>FROM</literal>. Toutes ces transformations produisent une table
virtuelle fournissant les lignes à passer à la liste de sélection qui
choisira les lignes à afficher de la requête.
</para>
<sect2 id="queries-from">
<title>Clause <literal>FROM</literal></title>
<para>
La <xref linkend="sql-from" endterm="sql-from-title"/> dérive une
table à partir d'une ou plusieurs tables données dans une liste de
référence dont les tables sont séparées par des virgules.
<synopsis>FROM <replaceable>reference_table</replaceable> <optional>, <replaceable>reference_table</replaceable> <optional>, ...</optional></optional></synopsis>
Une référence de table pourrait être un nom de table (avec en option
le nom du schéma) ou une table dérivée comme une sous-requête, une table
jointe ou une combinaison complexe de celles-ci. Si plus d'une référence de
tables est listée dans la clause <literal>FROM</literal>, elle sont jointes pour
former une table virtuelle intermédiaire qui pourrait être le sujet des
transformations des clauses <literal>WHERE</literal>, <literal>GROUP BY</literal>
et <literal>HAVING</literal>, et est finalement le résultat des expressions de
table.
</para>
<indexterm>
<primary>ONLY</primary>
</indexterm>
<para>
Lorsqu'une référence de table nomme une table qui est la table parent d'une
table suivant la hiérarchie de l'héritage, la référence de table produit les
lignes non seulement de la table mais aussi des descendants de cette table
sauf si le mot clé <literal>ONLY</literal> précède le nom de la table. Néanmoins,
la référence produit seulement les colonnes qui apparaissent dans la table
nommée... toute colonne ajoutée dans une sous-table est ignorée.
</para>
<sect3 id="queries-join">
<title>Tables jointes</title>
<indexterm zone="queries-join">
<primary>join</primary>
</indexterm>
<para>
Une table jointe est une table dérivée de deux autres tables (réelles ou
dérivées) suivant les règles du type de jointure particulier. Les
jointures internes (inner), externes (outer) et croisées (cross) sont
disponibles.
</para>
<variablelist>
<title>Types de jointures</title>
<varlistentry>
<term>Jointure croisée (cross join)</term>
<listitem>
<indexterm>
<primary>jointure</primary>
<secondary>croisée</secondary>
</indexterm>
<indexterm>
<primary>join</primary>
<secondary>cross</secondary>
</indexterm>
<indexterm>
<primary>jointure croisée</primary>
</indexterm>
<indexterm>
<primary>crossed joind</primary>
</indexterm>
<synopsis><replaceable>T1</replaceable> CROSS JOIN <replaceable>T2</replaceable></synopsis>
<para>
Pour chaque combinaison de lignes provenant de
<replaceable>T1</replaceable> et <replaceable>T2</replaceable>, la
table dérivée contiendra une ligne consistant de toutes les colonnes de
<replaceable>T1</replaceable> suivies de toutes les colonnes de
<replaceable>T2</replaceable>. Si les tables ont respectivement N et M
lignes, la table jointe en aura N * M.
</para>
<para>
<literal>FROM <replaceable>T1</replaceable> CROSS JOIN
<replaceable>T2</replaceable></literal> est équivalent à
<literal>FROM <replaceable>T1</replaceable>,
<replaceable>T2</replaceable></literal>. C'est aussi équivalent à
<literal>FROM <replaceable>T1</replaceable> INNER JOIN
<replaceable>T2</replaceable> ON TRUE</literal> (voir ci-dessous).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Jointures qualifiées (qualified joins)</term>
<listitem>
<indexterm>
<primary>join</primary>
<secondary>outer</secondary>
</indexterm>
<indexterm>
<primary>outer join</primary>
</indexterm>
<indexterm>
<primary>jointure</primary>
<secondary>externe</secondary>
</indexterm>
<indexterm>
<primary>jointure externe</primary>
</indexterm>
<synopsis><replaceable>T1</replaceable> { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable> ON <replaceable>expression_booleenne</replaceable>
<replaceable>T1</replaceable> { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable> USING ( <replaceable>liste des colonnes jointes</replaceable> )
<replaceable>T1</replaceable> NATURAL { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable></synopsis>
<para>
Les mots <literal>INNER</literal> et
<literal>OUTER</literal> sont optionnels dans toutes les formes.
<literal>INNER</literal> est la valeur par défaut ;
<literal>LEFT</literal>, <literal>RIGHT</literal> et
<literal>FULL</literal> impliquent une jointure externe.
</para>
<para>
La <firstterm>condition de la jointure</firstterm> est spécifiée dans
la clause <literal>ON</literal> ou <literal>USING</literal>, ou implicitement par le
mot <literal>NATURAL</literal>. La condition de jointure détermine les lignes
des deux tables source considérées comme <quote>correspondante</quote>,
comme l'explique le paragraphe ci-dessous.
</para>
<para>
La clause <literal>ON</literal> est le type le plus général de condition de
jointure : il prend une expression booléenne du même genre que
celle utilisée dans une clause <literal>WHERE</literal>. Une paires de lignes
de <replaceable>T1</replaceable> et <replaceable>T2</replaceable> correspondent si
l'expression <literal>ON</literal> est évaluée à vraie (true) pour ces deux
lignes.
</para>
<para>
<literal>USING</literal> est la notation raccourcie : elle prend une
liste de noms de colonnes, séparés par des virgules, que les tables
jointes ont en commun, et forme une condition de jointure spécifiant
l'égalité de chacune de ces paires de colonnes. De plus, la sortie de
<literal>JOIN USING</literal> a une colonne pour chaque paires égales des
colonnes en entrée, suivies par toutes les autres colonnes de chaque
table. Du coup, <literal>USING (a, b, c)</literal> est équivalent à
<literal>ON (t1.a = t2.a AND t1.b = t2.b AND t1.c = t2.c)</literal> avec
l'exception que si <literal>ON</literal> est utilisé, il y aura deux colonnes
<literal>a</literal>, <literal>b</literal>, puis <literal>c</literal> dans le résultat, alors
qu'avec <literal>USING</literal>, il n'y en aurait eu qu'une de chaque.
</para>
<para>
<indexterm>
<primary>join</primary>
<secondary>natural</secondary>
</indexterm>
<indexterm>
<primary>natural join</primary>
</indexterm>
<indexterm>
<primary>jointure</primary>
<secondary>naturelle</secondary>
</indexterm>
<indexterm>
<primary>jointure naturelle</primary>
</indexterm>
Enfin, <literal>NATURAL</literal> est un format raccourci de
<literal>USING</literal> : il forme une liste <literal>USING</literal>
consistant exactement des noms de colonnes apparaissant à la fois dans
les deux tables en entrée. Comme avec <literal>USING</literal>, ces colonnes
apparaissent seulement une fois dans la table de sortie.
</para>
<para>
Les types possibles de jointures qualifiées sont :
<variablelist>
<varlistentry>
<term><literal>INNER JOIN</literal></term>
<listitem>
<para>
Pour chaque ligne R1 de T1, la table jointe a une ligne pour chaque
ligne de T2 satisfaisant la condition de jointure avec R1.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>LEFT OUTER JOIN</literal></term>
<listitem>
<indexterm>
<primary>join</primary>
<secondary>left</secondary>
</indexterm>
<indexterm>
<primary>left join</primary>
</indexterm>
<indexterm>
<primary>jointure</primary>
<secondary>gauche</secondary>
</indexterm>
<indexterm>
<primary>jointure gauche</primary>
</indexterm>
<para>
Tout d'abord, une jointure interne est réalisée. Puis, pour chaque
ligne de T1 qui ne satisfait pas la condition de jointure avec
les lignes de T2, une ligne jointe est ajoutée avec des valeurs
NULL dans les colonnes de T2. Du coup, la table jointe a au moins
une ligne pour chaque ligne de T1 quelque soient les conditions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>RIGHT OUTER JOIN</literal></term>
<listitem>
<indexterm>
<primary>join</primary>
<secondary>right</secondary>
</indexterm>
<indexterm>
<primary>right join</primary>
</indexterm>
<indexterm>
<primary>jointure</primary>
<secondary>droite</secondary>
</indexterm>
<indexterm>
<primary>jointure droite</primary>
</indexterm>
<para>
Tout d'abord, une jointure interne est réalisée. Puis, pour chaque
ligne de T2 qui ne satisfait pas la condition de jointure avec les
lignes de T1, une ligne jointe est ajoutée avec des valeurs NULL
dans les colonnes de T1. C'est l'inverse d'une jointure gauche :
la table résultante aura une ligne pour chaque ligne de T2 quelque
soient les conditions.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>FULL OUTER JOIN</literal></term>
<listitem>
<para>
Tout d'abord, une jointure interne est réalisée. Puis, pour chaque
ligne de T1 qui ne satisfait pas la condition de jointure avec les
lignes de T2, une ligne jointe est ajoutée avec des valeurs NULL dans
les colonnes de T2. De plus, pour chaque ligne de T2 qui ne satisfait
pas la condition de jointure avec les lignes de T1, une ligne jointe
est ajoutée avec des valeurs NULL dans les colonnes de T1.
</para>
</listitem>
</varlistentry>
</variablelist>
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
Les jointures de tous les types peuvent être chaînées ensemble ou
imbriquées : soit les deux soit une des deux, parmi
<replaceable>T1</replaceable> et <replaceable>T2</replaceable>, peuvent
être des tables. Les parenthèses peuvent être utilisées autour des clauses
<literal>JOIN</literal> pour contrôler l'ordre de jointure. En l'absence de
parenthèses, les clauses <literal>JOIN</literal> sont imbriquées de gauche à
droite.
</para>
<para>
Pour rassembler tout ceci, supposons que nous avons une table
<literal>t1</literal> :
<programlisting> no | nom
----+------
1 | a
2 | b
3 | c</programlisting>
et une table <literal>t2</literal> :
<programlisting> no | valeur
----+-------
1 | xxx
3 | yyy
5 | zzz</programlisting>
nous obtenons les résultats suivants pour les différentes jointures :
<screen><prompt>=></prompt> <userinput>SELECT * FROM t1 CROSS JOIN t2;</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
1 | a | 3 | yyy
1 | a | 5 | zzz
2 | b | 1 | xxx
2 | b | 3 | yyy
2 | b | 5 | zzz
3 | c | 1 | xxx
3 | c | 3 | yyy
3 | c | 5 | zzz
(9 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 INNER JOIN t2 ON t1.no = t2.no;</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
3 | c | 3 | yyy
(2 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 INNER JOIN t2 USING (no);</userinput>
no | nom | valeur
----+-----+-------
1 | a | xxx
3 | c | yyy
(2 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 NATURAL INNER JOIN t2;</userinput>
no | nom | valeur
----+-----+-------
1 | a | xxx
3 | c | yyy
(2 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 ON t1.no = t2.no;</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
2 | b | |
3 | c | 3 | yyy
(3 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 USING (no);</userinput>
no | nom | valeur
----+-----+-------
1 | a | xxx
2 | b |
3 | c | yyy
(3 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 RIGHT JOIN t2 ON t1.no = t2.no;</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
3 | c | 3 | yyy
| | 5 | zzz
(3 rows)
<prompt>=></prompt> <userinput>SELECT * FROM t1 FULL JOIN t2 ON t1.no = t2.no;</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
2 | b | |
3 | c | 3 | yyy
| | 5 | zzz
(4 rows)</screen>
</para>
<para>
La condition de jointure spécifiée avec <literal>ON</literal> peut aussi contenir
des conditions sans relation directe avec la jointure. Ceci est utile
pour quelques requêtes mais son utilisation doit avoir été réfléchie. Par
exemple :
<screen><prompt>=></prompt> <userinput>SELECT * FROM t1 LEFT JOIN t2 ON t1.no = t2.no AND t2.valeur = 'xxx';</userinput>
no | nom | no | valeur
----+-----+----+-------
1 | a | 1 | xxx
2 | b | |
3 | c | |
(3 rows)</screen>
</para>
</sect3>
<sect3 id="queries-table-aliases">
<title>Alias de table et de colonne</title>
<indexterm zone="queries-table-aliases">
<primary>alias</primary>
<secondary>dans la clause FROM</secondary>
</indexterm>
<indexterm>
<primary>label</primary>
<see>alias</see>
</indexterm>
<para>
Un nom temporaire peut être donné aux tables et aux références de tables
complexe, qui sera ensuite utilisé pour référencer la table dérivée dans la
suite de la requête. Cela s'appelle un <firstterm>alias de
table</firstterm>.
</para>
<para>
Pour créer un alias de table, écrivez
<synopsis>FROM <replaceable>reference_table</replaceable> AS <replaceable>alias</replaceable></synopsis>
ou
<synopsis>FROM <replaceable>reference_table</replaceable> <replaceable>alias</replaceable></synopsis>
Le mot clé <literal>AS</literal> n'est pas obligatoire.
<replaceable>alias</replaceable> peut être tout identifiant.
</para>
<para>
Une application typique des alias de table est l'affectation d'identifieurs
courts pour les noms de tables longs, ce qui permet de garder des clauses de
jointures lisibles. Par exemple :
<programlisting>SELECT * FROM nom_de_table_tres_tres_long s
JOIN un_autre_nom_tres_long a ON s.id = a.no;</programlisting>
</para>
<para>
L'alias devient le nouveau nom de référence de la table pour la requête
courante — il n'est plus possible de référencer la table avec son nom
d'origine. Du coup :
<programlisting>SELECT * FROM ma_table AS m WHERE ma_table.a > 5;</programlisting>
n'est pas valide suivant le standard SQL. Dans
<productname>PostgreSQL</productname>, ceci amènera une erreur si la variable
<xref linkend="guc-add-missing-from"/> est désactivée (<literal>off</literal>,
valeur par défaut).
S'il est activé (<literal>on</literal>), une référence vers une table
implicite sera ajoutée à la clause <literal>FROM</literal>, de façon à ce que
la requête soit exécutée comme si elle était écrite ainsi :
<programlisting>SELECT * FROM ma_table AS m, ma_table AS ma_table WHERE ma_table.a > 5;</programlisting>
Cela résultera en une jointure croisée, ce qui n'est habituellement pas
ce que vous voulez.
</para>
<para>
Les alias de table sont disponibles principalement pour aider à l'écriture
de requête mais ils deviennent nécessaires pour joindre une table avec
elle-même, par exemple :
<programlisting>SELECT * FROM personnes AS mere JOIN personnes AS enfant ON mere.id = enfant.mere_id;
</programlisting>
De plus, un alias est requis si la référence de la table est une
sous-requête (voir la <xref linkend="queries-subqueries"/>).
</para>
<para>
Les parenthèses sont utilisées pour résoudre les ambiguïtés. Dans l'exemple
suivant, la première instruction affecte l'alias <literal>b</literal> à la
deuxième instance de <literal>ma_table</literal> mais la deuxième instruction
affecte l'alias au résultat de la jonction :
<programlisting>SELECT * FROM ma_table AS a CROSS JOIN ma_table AS b ...
SELECT * FROM (ma_table AS a CROSS JOIN ma_table) AS b ...</programlisting>
</para>
<para>
Une autre forme d'alias de tables donne des noms temporaires aux colonnes
de la table ainsi qu'à la table :
<synopsis>FROM <replaceable>reference_table</replaceable> <optional>AS</optional> <replaceable>alias</replaceable> ( <replaceable>colonne1</replaceable> <optional>, <replaceable>colonne2</replaceable> <optional>, ...</optional></optional> )</synopsis>
Si le nombre d'alias de colonnes spécifié est plus petit que le nombre
de colonnes dont dispose la table réelle, les colonnes suivantes ne sont
pas renommées. Cette syntaxe est particulièrement utile dans le cas de
jointure avec la même table ou dans le cas de sous-requêtes.
</para>
<para>
Quand un alias est appliqué à la sortie d'une clause <literal>JOIN</literal> en
utilisant n'importe laquelle de ces formes, l'alias cache le nom original à
l'intérieur du <literal>JOIN</literal>. Par exemple :
<programlisting>SELECT a.* FROM ma_table AS a JOIN ta_table AS b ON ...</programlisting>
est du SQL valide mais :
<programlisting>SELECT a.* FROM (ma_table AS a JOIN ta_table AS b ON ...) AS c</programlisting>
n'est pas valide : l'alias de table <literal>a</literal> n'est pas visible
en dehors de l'alias <literal>c</literal>.
</para>
</sect3>
<sect3 id="queries-subqueries">
<title>Sous-requêtes</title>
<indexterm zone="queries-subqueries">
<primary>sous-requête</primary>
</indexterm>
<para>
Une sous-requête spécifiant une table dérivée doit être enfermée
dans des parenthèses et <emphasis>doit</emphasis> se voir affecté un alias
de table (voir la <xref linkend="queries-table-aliases"/>). Par
exemple :
<programlisting>FROM (SELECT * FROM table1) AS nom_alias</programlisting>
</para>
<para>
Cet exemple est équivalent à <literal>FROM table1 AS
nom_alias</literal>. Des cas plus intéressants, qui ne peuvent pas être
réduit à une jointure pleine, surviennent quand la sous-requête implique un
groupement ou un agrégat.
</para>
<para>
Uns sous-requête peut aussi être une liste <command>VALUES</command> :
<programlisting>
FROM (VALUES ('anne', 'smith'), ('bob', 'jones'), ('joe', 'blow'))
AS noms(prenom, nom)
</programlisting>
De nouveau, un alias de table est requis. Affecter des noms d'alias aux
colonnes de la liste <command>VALUES</command> est en option mais c'est
une bonne pratique. Pour plus d'informations, voir
<xref linkend="queries-values"/>.
</para>
</sect3>
<sect3 id="queries-tablefunctions">
<title>Fonctions de table</title>
<indexterm zone="queries-tablefunctions"><primary>fonction de table</primary></indexterm>
<indexterm zone="queries-tablefunctions">
<primary>fonction</primary>
<secondary>dans la clause FROM</secondary>
</indexterm>
<para>
Les fonctions de table sont des fonctions produisant un ensemble de
lignes composées de types de données de base (types scalaires) ou de types
de données composites (lignes de table). Elles sont utilisées comme une
table, une vue ou une sous-requête de la clause <literal>FROM</literal> d'une
requête. Les colonnes renvoyées par les fonctions de table peuvent être
incluses dans une clause <literal>SELECT</literal>, <literal>JOIN</literal> ou
<literal>WHERE</literal> de la même manière qu'une colonne de table, vue ou
sous-requête.
</para>
<para>
Si une fonction de table renvoie un type de données de base, la colonne
de résultat est nommée comme la fonction. Si la fonction renvoie un type
composite, les colonnes résultantes ont le même nom que les attributs
individuels du type.
</para>
<para>
Une fonction de table peut avoir un alias dans la clause
<literal>FROM</literal> mais elle peut être laissée sans alias. Si une
fonction est utilisée dans la clause <literal>FROM</literal> sans alias, le nom de
la fonction est utilisé comme nom de table résultante.
</para>
<para>
Quelques exemples :
<programlisting>CREATE TABLE truc (trucid int, trucsousid int, trucnom text);
CREATE FUNCTION recuptruc(int) RETURNS SETOF foo AS $$
SELECT * FROM truc WHERE trucid = $1;
$$ LANGUAGE SQL;
SELECT * FROM recuptruc(1) AS t1;
SELECT * FROM truc
WHERE trucsousid IN (select trucsousid from recuptruc(truc.trucid) z
where z.trucid = truc.trucid);
CREATE VIEW vue_recuptruc AS SELECT * FROM recuptruc(1);
SELECT * FROM vue_recuptruc;</programlisting>
</para>
<para>
Dans certains cas, il est utile de définir des fonctions de table pouvant
renvoyer des ensembles de colonnes différentes suivant la façon dont elles
sont appelées. Pour supporter ceci, la fonction de table est déclarée comme
renvoyant le pseudotype <type>record</type>. Quand une telle fonction est
utilisée dans une requête, la structure de ligne attendue doit être
spécifiée dans la requête elle-même, de façon à ce que le système sache
comment analyser et planifier la requête. Considérez cet exemple :
<programlisting>SELECT *
FROM dblink('dbname=mabd', 'select proname, prosrc from pg_proc')
AS t1(proname nom, prosrc text)
WHERE proname LIKE 'bytea%';</programlisting>
La fonction <literal>dblink</literal> exécute une requête distante (voir
<filename>contrib/dblink</filename>). Elle déclare renvoyer le type
<type>record</type> car elle pourrait être utilisée pour tout type de requête.
L'ensemble de colonnes réelles doit être spécifié dans la requête
appelante de façon à ce que l'analyseur sache, par exemple, comment
étendre <literal>*</literal>.
</para>
</sect3>
</sect2>
<sect2 id="queries-where">
<title>Clause <literal>WHERE</literal></title>
<indexterm zone="queries-where">
<primary>WHERE</primary>
</indexterm>
<para>
La syntaxe de la <xref linkend="sql-where" endterm="sql-where-title"/> est
<synopsis>WHERE <replaceable>condition_recherche</replaceable></synopsis>
où <replaceable>condition_recherche</replaceable> est toute expression de
valeur (voir la <xref linkend="sql-expressions"/>) renvoyant une valeur
de type <type>boolean</type>.
</para>
<para>
Après le traitement de la clause <literal>FROM</literal>, chaque ligne de la
table virtuelle dérivée est vérifiée avec la condition de recherche. Si le
résultat de la vérification est positif (true), la ligne est conservée dans
la table de sortie, sinon (c'est-à-dire si le résultat est faux ou nul), la
ligne est abandonnée. La condition de recherche référence typiquement au
moins quelques colonnes de la table générée dans la clause
<literal>FROM</literal> ; ceci n'est pas requis mais, dans le cas contraire,
la clause <literal>WHERE</literal> n'aurait aucune utilité.
</para>
<note>
<para>
La condition de jointure d'une jointure interne peut être écrite soit dans
la clause <literal>WHERE</literal> soit dans la clause <literal>JOIN</literal>. Par
exemple, ces expressions de tables sont équivalentes :
<programlisting>FROM a, b WHERE a.id = b.id AND b.val > 5</programlisting>
et :
<programlisting>FROM a INNER JOIN b ON (a.id = b.id) WHERE b.val > 5</programlisting>
ou même peut-être :
<programlisting>FROM a NATURAL JOIN b WHERE b.val > 5</programlisting>
Laquelle vous utilisez est plutôt une affaire de style. La syntaxe
<literal>JOIN</literal> dans la clause <literal>FROM</literal> n'est probablement pas
aussi portable vers les autres systèmes de gestion de bases de données SQL.
Pour les jointures externes, il n'y a pas d'autres choix : elles
doivent être faites dans la clause <literal>FROM</literal>. Une clause
<literal>ON</literal>/<literal>USING</literal> d'une jointure externe n'est
<emphasis>pas</emphasis> équivalente à une condition <literal>WHERE</literal> parce
qu'elle détermine l'ajout de lignes (pour les lignes qui ne correspondent
pas en entrée) ainsi que pour la suppression de lignes dans le résultat
final.
</para>
</note>
<para>
Voici quelques exemples de clauses <literal>WHERE</literal> :
<programlisting>SELECT ... FROM fdt WHERE c1 > 5
SELECT ... FROM fdt WHERE c1 IN (1, 2, 3)
SELECT ... FROM fdt WHERE c1 IN (SELECT c1 FROM t2)
SELECT ... FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10)
SELECT ... FROM fdt WHERE c1 BETWEEN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100
SELECT ... FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)</programlisting>
<literal>fdt</literal> est la table dérivée dans la clause
<literal>FROM</literal>. Les lignes qui ne correspondent pas à la condition de
recherche de la clause <literal>WHERE</literal> sont éliminées de la table
<literal>fdt</literal>. Notez l'utilisation de sous-requêtes scalaires en
tant qu'expressions de valeurs. Comme n'importe quelle autre requête, les
sous-requêtes peuvent employer des expressions de tables complexes. Notez
aussi comment <literal>fdt</literal> est référencée dans les sous-requêtes.
Qualifier <literal>c1</literal> comme <literal>fdt.c1</literal> est seulement nécessaire
si <literal>c1</literal> est aussi le nom d'une colonne dans la table d'entrée
dérivée de la sous-requête. Mais qualifier le nom de colonne ajoute à la
clarté même lorsque cela n'est pas nécessaire. Cet exemple montre comment
le nom de colonne d'une requête externe est étendue dans les requêtes
internes.
</para>
</sect2>
<sect2 id="queries-group">
<title>Clauses <literal>GROUP BY</literal> et
<literal>HAVING</literal></title>
<indexterm zone="queries-group">
<primary>GROUP BY</primary>
</indexterm>
<indexterm zone="queries-group">
<primary>groupement</primary>
</indexterm>
<para>
Après avoir passé le filtre <literal>WHERE</literal>, la table d'entrée dérivée
peut être sujette à un regroupement en utilisant la clause <literal>GROUP
BY</literal> et à une élimination de groupe de lignes avec la clause
<literal>HAVING</literal>.
</para>
<synopsis>SELECT <replaceable>liste_selection</replaceable>
FROM ...
<optional>WHERE ...</optional>
GROUP BY <replaceable>reference_colonne_regroupement</replaceable><optional>,<replaceable>reference_colonne_regroupement</replaceable></optional>...</synopsis>
<para>
La <xref linkend="sql-groupby" endterm="sql-groupby-title"/> est
utilisée pour regrouper les lignes d'une table partageant les mêmes valeurs
dans toutes les colonnes précisées. L'ordre dans lequel ces colonnes sont
indiquées importe peu. L'effet est de combiner chaque ensemble de lignes
partageant des valeurs communes en un seul groupe de ligne représentant
toutes les lignes du groupe. Ceci est fait pour éliminer les redondances dans
la sortie et/ou pour calculer les agrégats s'appliquant à ces groupes. Par
exemple :
<screen><prompt>=></prompt> <userinput>SELECT * FROM test1;</userinput>
x | y
---+---
a | 3
c | 2
b | 5
a | 1
(4 rows)
<prompt>=></prompt> <userinput>SELECT x FROM test1 GROUP BY x;</userinput>
x
---
a
b
c
(3 rows)</screen>
</para>
<para>
Dans la seconde requête, nous n'aurions pas pu écrire <literal>SELECT *
FROM test1 GROUP BY x</literal> parce qu'il n'existe pas une seule valeur
pour la colonne <literal>y</literal> pouvant être associé avec chaque autre groupe.
Les colonnes de regroupement peuvent être référencées dans la liste de
sélection car elles ont une valeur constante unique par groupe.
</para>
<para>
En général, si une table est groupée, les colonnes qui ne sont pas
utilisées dans le regroupement ne peuvent pas être référencées sauf dans les
expressions d'agrégats. Voici un exemple d'expressions d'agrégat :
<screen><prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x;</userinput>
x | sum
---+-----
a | 4
b | 5
c | 2
(3 rows)</screen>
Ici, <literal>sum</literal> est la fonction d'agrégat qui calcule une seule
valeur pour le groupe entier. La <xref linkend="functions-aggregate"/>
propose plus d'informations sur les fonctions d'agrégats disponibles.
</para>
<tip>
<para>
Le regroupement sans expressions d'agrégats calcule effectivement
l'ensemble les valeurs distinctes d'une colonne. Ceci peut aussi se faire
en utilisant la clause <literal>DISTINCT</literal> (voir la <xref
linkend="queries-distinct"/>).
</para>
</tip>
<para>
Voici un autre exemple : il calcule les ventes totales pour chaque
produit (plutôt que le total des ventes sur tous les produits) :
<programlisting>SELECT produit_id, p.nom, (sum(v.unite) * p.prix) AS ventes
FROM produits p LEFT JOIN ventes v USING (produit_id)
GROUP BY produit_id, p.nom, p.prix;</programlisting>
Dans cet exemple, les colonnes <literal>produit_id</literal>,
<literal>p.nom</literal> et <literal>p.prix</literal> doivent être dans la
clause <literal>GROUP BY</literal> car elles sont référencées dans la liste de
sélection de la requête (suivant la façon dont est conçue la table
produits, le nom et le prix pourraient être totalement dépendants de l'ID du
produit, donc des regroupements supplémentaires pourraient théoriquement
être inutiles mais ceci n'est pas encore implémenté). La colonne
<literal>s.unite</literal> n'a pas besoin d'être dans la liste <literal>GROUP
BY</literal> car elle est seulement utilisée dans l'expression de l'agrégat
(<literal>sum(...)</literal>) représentant les ventes d'un produit. Pour
chaque produit, la requête renvoie une ligne de résumé sur les ventes de ce
produit.
</para>
<para>
En SQL strict, <literal>GROUP BY</literal> peut seulement grouper les colonnes de
la table source mais <productname>PostgreSQL</productname> étend ceci en
autorisant <literal>GROUP BY</literal> à grouper aussi les colonnes de la liste de
sélection. Grouper par expressions de valeurs au lieu de simples noms de
colonnes est aussi permis.
</para>
<indexterm>
<primary>HAVING</primary>
</indexterm>
<para>
Si une table a été groupée en utilisant la clause <literal>GROUP
BY</literal> mais que seuls certains groupes sont intéressants, la clause
<literal>HAVING</literal> peut être utilisée, comme une clause
<literal>WHERE</literal>, pour éliminer les groupes d'une table groupée. Voici la
syntaxe :
<synopsis>SELECT <replaceable>liste_selection</replaceable> FROM ... <optional>WHERE ...</optional> GROUP BY ... HAVING <replaceable>expression_booléenne</replaceable></synopsis>
Les expressions de la clause <literal>HAVING</literal> peuvent référer à la fois
aux expressions groupées et aux expressions non groupées (ce qui impliquent
nécessairement une fonction d'agrégat).
</para>
<para>
Exemple :
<screen><prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;</userinput>
x | sum
---+-----
a | 4
b | 5
(2 rows)
<prompt>=></prompt> <userinput>SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';</userinput>
x | sum
---+-----
a | 4
b | 5
(2 rows)</screen>
</para>
<para>
De nouveau, un exemple plus réaliste :
<programlisting>SELECT produit_id, p.nom, (sum(v.unite) * (p.prix - p.cout)) AS profit
FROM produits p LEFT JOIN ventes v USING (produit_id)
WHERE v.date > CURRENT_DATE - INTERVAL '4 weeks'
GROUP BY produit_id, p.nom, p.prix, p.cout
HAVING sum(p.prix * s.unite) > 5000;</programlisting>
Dans l'exemple ci-dessus, la clause <literal>WHERE</literal> sélectionne les
lignes par une colonne qui n'est pas groupée (l'expression est vraie
seulement pour les ventes des quatre dernières semaines) alors que la
clause <literal>HAVING</literal> restreint la sortie aux groupes dont le total des
ventes dépasse 5000. Notez que les expressions d'agrégats n'ont pas besoin
d'être identiques dans toutes les parties d'une requête.
</para>
</sect2>
</sect1>
<sect1 id="queries-select-lists">
<title>Listes de sélection</title>
<indexterm>
<primary>SELECT</primary>
<secondary>liste de sélection</secondary>
</indexterm>
<para>
Comme montré dans la section précédente, l'expression de table pour la
commande <command>SELECT</command> construit une table virtuelle intermédiaire
en combinant les tables, vues, en éliminant les lignes, en groupant, etc. Cette
table est finalement passée à la réalisation de la <firstterm>liste de
sélection</firstterm>. Cette liste détermine les <emphasis>colonnes</emphasis>
de la table intermédiaire à afficher.
</para>
<sect2 id="queries-select-list-items">
<title>Éléments de la liste de sélection</title>
<indexterm>
<primary>*</primary>
</indexterm>
<para>
La forme la plus simple de liste de sélection est <literal>*</literal>.
C'est un raccourci pour indiquer toutes les colonnes que l'expression de
table produit. Sinon, une liste de sélection est une liste d'expressions
de valeurs séparées par des virgules (comme défini dans la <xref
linkend="sql-expressions"/>). Par exemple, cela pourrait être une liste des
noms de colonnes :
<programlisting>SELECT a, b, c FROM ...</programlisting>
Les noms de colonnes <literal>a</literal>, <literal>b</literal> et <literal>c</literal> sont
soit les noms actuels des colonnes des tables référencées dans la clause
<literal>FROM</literal> soit les alias qui leur ont été donnés (voir l'explication
dans <xref linkend="queries-table-aliases"/>). L'espace de nom disponible
dans la liste de sélection est le même que dans la clause <literal>WHERE</literal>
sauf si le regroupement est utilisé, auquel cas c'est le même que dans la
clause <literal>HAVING</literal>.
</para>
<para>
Si plus d'une table a une colonne du même nom, le nom de la table doit
aussi être donné comme dans :
<programlisting>SELECT tbl1.a, tbl2.a, tbl1.b FROM ...</programlisting>
En travaillant avec plusieurs tables, il est aussi utile de demander toutes
les colonnes d'une table particulière :
<programlisting>SELECT tbl1.*, tbl2.a FROM ...</programlisting>
(voir aussi la <xref linkend="queries-where"/>)
</para>
<para>
Si une expression de valeur arbitraire est utilisée dans la liste de
sélection, il ajoute conceptuellement une nouvelle colonne virtuelle dans la
table renvoyée. L'expression de valeur est évaluée une fois pour chaque
ligne avec une substitution des valeurs de lignes avec les références de
colonnes. Mais les expressions de la liste de sélection n'ont pas à
référencer les colonnes dans l'expression de la table de la clause
<literal>FROM</literal> ; elles pourrait être des expressions arithmétiques
constantes, par exemple.
</para>
</sect2>
<sect2 id="queries-column-labels">