PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 12.22 » Référence » Commandes SQL » SELECT

SELECT

SELECT, TABLE, WITH — rĂ©cupĂšre des lignes d'une table ou d'une vue

Synopsis

[ WITH [ RECURSIVE ] requĂȘte_with [, ...] ]
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
    [ { * | expression [ [ AS ] nom_sortie ] } [, ...] ]
    [ FROM éléments_from [, ...] ]
    [ WHERE condition ]
    [ GROUP BY element_regroupement [, ...] ]
    [ HAVING condition ]
    [ WINDOW nom_window AS ( définition_window ) [, ...] ]
    [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] select ]
    [ ORDER BY expression [ ASC | DESC | USING opérateur ] [ NULLS { FIRST | LAST } ] [, ...] ]
    [ LIMIT { nombre | ALL } ]
    [ OFFSET début ] [ ROW | ROWS ] ]
    [ FETCH { FIRST | NEXT } [ total ] { ROW | ROWS } ONLY ]
    [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF nom_table [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

avec Ă©lĂ©ments_from qui peut ĂȘtre :

    [ ONLY ] nom_table [ * ] [ [ AS ] alias [ ( alias_colonne [, ...] ) ] ]
                [ TABLESAMPLE methode_echantillonnage ( argument [, ...] ) [ REPEATABLE ( pourcentage_echantillon ) ] ]
    [ LATERAL ] ( select ) [ AS ] alias [ ( alias_colonne [, ...] ) ]
    nom_requĂȘte_with [ [ AS ] alias [ ( alias_colonne [, ...] ) ] ]
    [ LATERAL ] nom_fonction ( [ argument [, ...] ] )
                [ WITH ORDINALITY ] [ [ AS ] alias [ ( alias_colonne [, ...] ) ] ]
    [ LATERAL ] nom_fonction ( [ argument [, ...] ] ) [ AS ] alias ( définition_colonne [, ...] )
     [ LATERAL ] nom_fonction ( [ argument [, ...] ] ) AS ( définition_colonne [, ...] )
    [ LATERAL ] ROWS FROM( nom_fonction ( [ argument [, ...] ] ) [ AS ( définition_colonne [, ...] ) ] [, ...] )
                [ WITH ORDINALITY ] [ [ AS ] alias [ ( alias_colonne [, ...] ) ] ]
    élément_from type_jointure élément_from { ON condition_jointure | USING ( colonne_jointure [, ...] ) }
    élément_from NATURAL type_jointure élément_from
    élément_from CROSS JOIN élément_from

et element_regroupement peut valoir :

    ( )
    expression
    ( expression [, ...] )
    ROLLUP ( { expression | ( expression [, ...] ) } [, ...] )
    CUBE ( { expression | ( expression [, ...] ) } [, ...] )
    GROUPING SETS ( element_regroupement [, ...] )

et requĂȘte_with est :

    nom_requĂȘte_with [ ( nom_colonne [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( select | valeurs | insert | update | delete )

TABLE [ ONLY ] nom_table [ * ]
  

Description

SELECT rĂ©cupĂšre des lignes de zĂ©ro ou plusieurs tables. Le traitement gĂ©nĂ©ral de SELECT est le suivant :

  1. Toutes les requĂȘtes dans la liste WITH sont Ă©valuĂ©es. Elles jouent le rĂŽle de tables temporaires qui peuvent ĂȘtre rĂ©fĂ©rencĂ©es dans la liste FROM. Une requĂȘte WITH qui est rĂ©fĂ©rencĂ©e plus d'une fois dans FROM n'est calculĂ©e qu'une fois, unless specified otherwise with NOT MATERIALIZED (voir la section intitulĂ©e « Clause WITH Â» ci-dessous).

  2. Tous les Ă©lĂ©ments de la liste FROM sont calculĂ©s. (Chaque Ă©lĂ©ment dans la liste FROM est une table rĂ©elle ou virtuelle.) Si plus d'un Ă©lĂ©ment sont spĂ©cifiĂ©s dans la liste FROM, ils font l'objet d'une jointure croisĂ©e (cross-join). (Voir la section intitulĂ©e « Clause FROM Â» ci-dessous.)

  3. Si la clause WHERE est spĂ©cifiĂ©e, toutes les lignes qui ne satisfont pas les conditions sont Ă©liminĂ©es de l'affichage. (Voir la section intitulĂ©e « Clause WHERE Â» ci-dessous.)

  4. Si la clause GROUP BY est spĂ©cifiĂ©e or if there are aggregate function calls, l'affichage est divisĂ© en groupes de lignes qui correspondent Ă  une ou plusieurs valeurs, et aux rĂ©sultats des fonctions d'agrĂ©gat calculĂ©s. Si la clause HAVING est prĂ©sente, elle Ă©limine les groupes qui ne satisfont pas la condition donnĂ©e. (Voir Clause GROUP BY et Clause HAVING ci-dessous.) Bien que les colonnes en sortie d'une requĂȘte sont calculĂ©es nominalement Ă  la prochaine Ă©tape, elles peuvent aussi ĂȘtre rĂ©fĂ©rencĂ©es (par nom ou numĂ©ro) dans la clause GROUP BY.

  5. Les lignes retournĂ©es sont traitĂ©es en utilisant les expressions de sortie de SELECT pour chaque ligne ou groupe de ligne sĂ©lectionnĂ©. (Voir la section intitulĂ©e « Liste SELECT Â» ci-dessous.)

  6. SELECT DISTINCT élimine du résultat les lignes en double. SELECT DISTINCT ON élimine les lignes qui correspondent sur toute l'expression spécifiée. SELECT ALL (l'option par défaut) retourne toutes les lignes, y compris les doublons. (cf. DISTINCT Clause ci-dessous.)

  7. En utilisant les opĂ©rateurs UNION, INTERSECT et EXCEPT, l'affichage de plusieurs instructions SELECT peut ĂȘtre combinĂ© pour former un ensemble unique de rĂ©sultats. L'opĂ©rateur UNION renvoie toutes les lignes qui appartiennent, au moins, Ă  l'un des ensembles de rĂ©sultats. L'opĂ©rateur INTERSECT renvoie toutes les lignes qui sont dans tous les ensembles de rĂ©sultats. L'opĂ©rateur EXCEPT renvoie les lignes qui sont prĂ©sentes dans le premier ensemble de rĂ©sultats mais pas dans le deuxiĂšme. Dans les trois cas, les lignes dupliquĂ©es sont Ă©liminĂ©es sauf si ALL est spĂ©cifiĂ©. Le mot-clĂ© supplĂ©mentaire DISTINCT peut ĂȘtre ajoutĂ© pour signifier explicitement que les lignes en doublon sont Ă©liminĂ©es. Notez bien que DISTINCT est lĂ  le comportement par dĂ©faut, bien que ALL soit le dĂ©faut pour la commande SELECT. (Voir la section intitulĂ©e « Clause UNION Â», la section intitulĂ©e « Clause INTERSECT Â» et la section intitulĂ©e « Clause EXCEPT Â» ci-dessous.)

  8. Si la clause ORDER BY est spĂ©cifiĂ©e, les lignes renvoyĂ©es sont triĂ©es dans l'ordre spĂ©cifiĂ©. Si ORDER BY n'est pas indiquĂ©, les lignes sont retournĂ©es dans l'ordre qui permet la rĂ©ponse la plus rapide du systĂšme. (Voir la section intitulĂ©e « Clause ORDER BY Â» ci-dessous.)

  9. Si les clauses LIMIT (ou FETCH FIRST) ou OFFSET sont spĂ©cifiĂ©es, l'instruction SELECT ne renvoie qu'un sous-ensemble de lignes de rĂ©sultats. (Voir la section intitulĂ©e « Clause LIMIT Â» ci-dessous.)

  10. Si la clause FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE ou FOR KEY SHARE est spĂ©cifiĂ©e, l'instruction SELECT verrouille les lignes sĂ©lectionnĂ©es contre les mises Ă  jour concurrentes. (Voir la section intitulĂ©e « Clause de verrouillage Â» ci-dessous.)

Le droit SELECT sur chaque colonne utilisée dans une commande SELECT est nécessaire pour lire ses valeurs. L'utilisation de FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE ou FOR KEY SHARE requiert en plus le droit UPDATE (pour au moins une colonne de chaque table sélectionnée).

ParamĂštres

Clause WITH

La clause WITH vous permet de spĂ©cifier une ou plusieurs sous-requĂȘtes qui peuvent ĂȘtre utilisĂ©es par leur nom dans la requĂȘte principale. Les sous-requĂȘtes se comportent comme des tables temporaires ou des vues pendant la durĂ©e d'exĂ©cution de la requĂȘte principale. Chaque sous-requĂȘte peut ĂȘtre un ordre SELECT, TABLE, VALUES, INSERT, UPDATE ou bien DELETE. Lorsque vous Ă©crivez un ordre de modification de donnĂ©es (INSERT, UPDATE ou DELETE) dans une clause WITH, il est habituel d'inclure une clause RETURNING. C'est la sortie de cette clause RETURNING, et non pas la table sous-jacente que l'ordre modifie, qui donne lieu Ă  la table temporaire lue par la requĂȘte principale. Si la clause RETURNING est omise, l'ordre est tout de mĂȘme exĂ©cutĂ©, mais il ne produit pas de sortie ; il ne peut donc pas ĂȘtre rĂ©fĂ©rencĂ© comme une table par la requĂȘte principale.

Un nom (sans qualification de schĂ©ma) doit ĂȘtre spĂ©cifiĂ© pour chaque requĂȘte WITH. En option, une liste de noms de colonnes peut ĂȘtre spĂ©cifiĂ© ; si elle est omise, les noms de colonnes sont dĂ©duites de la sous-requĂȘte.

Si RECURSIVE est spĂ©cifiĂ©, la sous-requĂȘte SELECT peut se rĂ©fĂ©rencer elle mĂȘme. Une sous-requĂȘte de ce type doit avoir la forme

terme_non_récursif UNION [ ALL | DISTINCT ] terme_récursif
    

oĂč l'auto-rĂ©fĂ©rence rĂ©cursive doit apparaĂźtre dans la partie droite de l'UNION. Seule une auto-rĂ©fĂ©rence rĂ©cursive est autorisĂ©e par requĂȘte. Les ordres de modification rĂ©cursifs ne sont pas supportĂ©s, mais vous pouvez utiliser le rĂ©sultat d'une commande SELECT rĂ©cursive dans un ordre de modification. Voir Section 7.8 pour un exemple.

Un autre effet de RECURSIVE est que les requĂȘtes WITH n'ont pas besoin d'ĂȘtre ordonnĂ©es : une requĂȘte peut en rĂ©fĂ©rencer une autre qui se trouve plus loin dans la liste (toutefois, les rĂ©fĂ©rences circulaires, ou rĂ©cursion mutuelle, ne sont pas implĂ©mentĂ©es). Sans RECURSIVE, les requĂȘtes WITH ne peuvent rĂ©fĂ©rencer d'autres requĂȘtes WITH soƓurs que si elles sont dĂ©clarĂ©es avant dans la liste WITH.

La requĂȘte principale et les requĂȘtes WITH sont toutes exĂ©cutĂ©es en mĂȘme temps. Ceci implique que les effets d'une requĂȘte modifiant des donnĂ©es dans la clause WITH ne peuvent pas ĂȘtre vus des autres parties de la requĂȘte, autrement qu'en lisant son retour avec la clause RETURNING. Si des telles instructions de modification de donnĂ©es essaient de modifier la mĂȘme ligne, les rĂ©sultats sont inconnus.

Quand il y a plusieurs requĂȘtes dans la clause WITH, RECURSIVE ne devra ĂȘtre Ă©crit qu'une seule fois, immĂ©diatement aprĂšs WITH. Cela s'applique Ă  toutes les requĂȘtes de la clause WITH, bien que cela n'a pas d'effet sur les requĂȘtes qui n'utilisent pas de rĂ©cursion de rĂ©fĂ©rence en avant (forward references).

Une propriĂ©tĂ© clĂ© des requĂȘtes WITH est qu'elles ne sont normalement Ă©valuĂ©es qu'une seule fois par exĂ©cution de la requĂȘte principale, mĂȘme si la 1requĂȘte principale les utilise plus d'une fois. En particulier, vous avez la garantie que les traitements de modification de donnĂ©es sont exĂ©cutĂ©s une seule et unique fois, que la requĂȘte principale lise tout ou partie de leur sortie.

NĂ©anmoins, une requĂȘte WITH peut ĂȘtre marquĂ©e NOT MATERIALIZED pour supprimer cette garantie. Dans ce cas, la requĂȘte WITH peut ĂȘtre intĂ©grĂ©e dans la requĂȘte principale comme s'il s'agissait d'un simple sous-SELECT dans la clause FROM de la requĂȘte principale. Ceci rĂ©sulte en des calculs dupliquĂ©es sur la requĂȘte principale fait rĂ©fĂ©rence Ă  la requĂȘte WITH plus d'une fois ; mais si chaque utilisation requiert seulement quelques lignes de la sortie complĂšte de la requĂȘte WITH, la clause NOT MATERIALIZED peut apporter un gain net en autorisant les requĂȘtes Ă  ĂȘtre optimisĂ©es globalement. NOT MATERIALIZED est ignorĂ© s'il est attachĂ© Ă  une requĂȘte WITH rĂ©cursive ou qui n'est pas sans effet de bord (autrement dit, pas un simple SELECT contenant aucune fonction volatile).

Par dĂ©faut, une requĂȘte WITH sans effet de bord est intĂ©grĂ©e dans la requĂȘte principale si elle est utilisĂ©e exactement une fois dans la clause FROM de la requĂȘte. Ceci permet une optimisation de la jointure des deux requĂȘtes dans des situations oĂč cela serait sĂ©mantiquement invisible. NĂ©anmoins, cette intĂ©gration peut ĂȘtre empĂȘchĂ©e en marquant la requĂȘte WITH avec le mot-clĂ© MATERIALIZED. Ceci peut ĂȘtre utile si la requĂȘte WITH est utilisĂ©e comme barriĂšre d'optimisation pour empĂȘcher le planificateur de choisir un mauvais plan. Les versions de PostgreSQL antĂ©rieures Ă  la 12 ne faisaient jamais ce type d'intĂ©gration, donc les requĂȘtes Ă©crites pour les versions prĂ©cĂ©dentes pourraient se fier sur WITH comme barriĂšres d'optimisation.

Voir Section 7.8 pour plus d'informations.

Clause FROM

La clause FROM spécifie une ou plusieurs tables source pour le SELECT. Si plusieurs sources sont spécifiées, le résultat est un produit cartésien (jointure croisée) de toutes les sources. Mais habituellement, des conditions de qualification (via WHERE) sont ajoutées pour restreindre les lignes renvoyées à un petit sous-ensemble du produit cartésien.

La clause FROM peut contenir les Ă©lĂ©ments suivants :

nom_table

Le nom (Ă©ventuellement qualifiĂ© par le nom du schĂ©ma) d'une table ou vue existante. Si ONLY est spĂ©cifiĂ© avant le nom de la table, seule cette table est parcourue. Dans le cas contraire, la table et toutes ses tables filles (s'il y en a) sont parcourues. En option, * peut ĂȘtre ajoutĂ© aprĂšs le nom de la table pour indiquer explicitement que les tables filles sont inclues.

alias

Un nom de substitution pour l'Ă©lĂ©ment FROM contenant l' alias. Un alias est utilisĂ© par briĂšvetĂ© ou pour lever toute ambiguĂŻtĂ© lors d'auto-jointures (la mĂȘme table est parcourue plusieurs fois). Quand un alias est fourni, il cache complĂštement le nom rĂ©el de la table ou fonction ; par exemple, avec FROM truc AS, le reste du SELECT doit faire rĂ©fĂ©rence Ă  cet Ă©lĂ©ment de FROM par f et non pas par truc. Si un alias est donnĂ©, une liste d' alias de colonnes peut aussi ĂȘtre saisi comme noms de substitution pour diffĂ©rentes colonnes de la table.

TABLESAMPLE methode_echantillonnage ( argument [, ...] ) [ REPEATABLE ( pourcentage_echantillon ) ]

Une clause TABLESAMPLE aprĂšs un nom_table indique que la methode_echantillonnage indiquĂ©e doit ĂȘtre utilisĂ© pour rĂ©cupĂ©rer un sous-ensemble des lignes de cette table. Cet Ă©chantillonnage prĂ©cĂšde l'application de tout autre filtre tel que la clause WHERE. La distribution standard de PostgreSQL inclut deux mĂ©thodes d'Ă©chantillonnage, BERNOULLIet SYSTEM mais d'autres mĂ©thodes d'Ă©chantillonnage peuvent ĂȘtre installĂ©es via des extensions.

Les mĂ©thodes d'Ă©chantillonnage BERNOULLI et SYSTEM acceptent chacune un seul argument correspondant Ă  la fraction Ă  Ă©chantillonner pour la table, exprimĂ©e sous la forme d'un pourcentage entre 0 et 100. Cet argument peut ĂȘtre une expression renvoyant un flottant (real). (D'autres mĂ©thodes d'Ă©chantillonnage pourraient accepter plus d'arguments ou des arguments diffĂ©rents.) Ces deux mĂ©thodes retournent chacune un sous-ensemble choisi au hasard de la table qui contiendra approximativement le pourcentage indiquĂ© de lignes pour cette table. La mĂ©thode BERNOULLI parcourt la table complĂšte et sĂ©lectionne ou ignore des lignes individuelles indĂ©pendemment avec la probabilitĂ© sĂ©lectionnĂ©e. La mĂ©thode SYSTEM fait un Ă©chantillonnage au niveau des blocs, chaque bloc ayant la chance indiquĂ©e d'ĂȘtre sĂ©lectionnĂ©e ; toutes les lignes de chaque bloc sĂ©lectionnĂ© sont renvoyĂ©es. La mĂ©thode SYSTEM est bien plus rapide que la mĂ©thode BERNOULLI quand un petit pourcentage est indiquĂ© pour l'Ă©chantillonnage mais elle peut renvoyer un Ă©chantillon moins alĂ©atoire de la table, dĂ» aux effets de l'ordre des lignes.

La clause optionnelle REPEATABLE indique un nombre seed ou une expression Ă  utiliser pour gĂ©nĂ©rer des nombres alĂ©atoires pour la mĂ©thode d'Ă©chantillonnage. La valeur peut ĂȘtre toute valeur flottante non NULL. Deux requĂȘtes prĂ©cisant la mĂȘme valeur seed et les mĂȘmes valeurs en argument sĂ©lectionneront le mĂȘme Ă©chantillon de la table si celle-ci n'a pas changĂ© entre temps. Mais diffĂ©rentes valeurs seed produiront gĂ©nĂ©ralement des Ă©chantillons diffĂ©rents. Si REPEATABLE n'est pas indiquĂ©, alors un nouvel Ă©chantillon est choisi au hasard pour chaque requĂȘte, basĂ© sur une graine gĂ©nĂ©rĂ©e par le systĂšme. Notez que certaines mĂ©thodes d'Ă©chantillonage supplĂ©mentaires pourraient ne pas accepter la clausse REPEATABLE, et toujours produire de nouveau Ă©chantillon Ă  chaque utilisation.

select

Un sous-SELECT peut apparaĂźtre dans la clause FROM. Il agit comme si sa sortie Ă©tait transformĂ©e en table temporaire pour la durĂ©e de cette seule commande SELECT. Le sous-SELECT doit ĂȘtre entourĂ© de parenthĂšses et un alias doit lui ĂȘtre fourni. Une commande VALUES peut aussi ĂȘtre utilisĂ©e ici.

requĂȘte_with

Une requĂȘte WITH est rĂ©fĂ©rencĂ©e par l'Ă©criture de son nom, exactement comme si le nom de la requĂȘte Ă©tait un nom de table (en fait, la requĂȘte WITH cache toutes les tables qui auraient le mĂȘme nom dans la requĂȘte principale. Si nĂ©cessaire, vous pouvez accĂ©der Ă  une table rĂ©elle du mĂȘme nom en prĂ©cisant le schĂ©ma du nom de la table). Un alias peut ĂȘtre indiquĂ© de la mĂȘme façon que pour une table.

nom_fonction

Des appels de fonctions peuvent apparaĂźtre dans la clause FROM. (Cela est particuliĂšrement utile pour les fonctions renvoyant des ensembles de rĂ©sultats, mais n'importe quelle fonction peut ĂȘtre utilisĂ©e.) Un appel de fonction agit comme si la sortie de la fonction Ă©tait créée comme une table temporaire pour la durĂ©e de cette seule commande SELECT. Quand la clause optionnelle WITH ORDINALITY est ajoutĂ©e Ă  l'appel de la fonction, une nouvelle colonne est ajoutĂ©e aprĂšs toutes les colonnes en sortie de la fonction numĂ©rotant ainsi chaque ligne.

Un alias peut ĂȘtre fourni de la mĂȘme façon pour une table. Si un alias de table est donnĂ©, une liste d'alias de colonnes peut aussi ĂȘtre Ă©crite pour fournir des noms de substitution pour un ou plusieurs attributs du type composite en retour de la fonction, ceci incluant la colonne ajoutĂ©e par ORDINALITY.

Plusieurs appels de fonction peuvent ĂȘtre combinĂ©s en un seul Ă©lĂ©ment dans la clause FROM en les entourant de ROWS FROM( ... ). La sortie d'un tel Ă©lĂ©ment est la concatĂ©nation de la premiĂšre ligne de chaque fonction, puis la deuxiĂšme ligne de chaque fonction, etc. Si certaines fonctions produisent moins de lignes que d'autres, des NULL sont ajoutĂ©es pour les donnĂ©es manquantes, ce qui permet d'avoir comme nombre de lignes celui de la fonction qui en renvoit le plus.

Si la fonction a Ă©tĂ© dĂ©finie comme renvoyant le type de donnĂ©es record, un alias ou le mot clĂ© AS doivent ĂȘtre prĂ©sents, suivi par une liste de dĂ©finition de colonnes de la forme ( nom_colonne type_donnĂ©e [, ... ]). La liste de dĂ©finition des colonnes doit correspondre au nombre rĂ©el et aux types rĂ©els des colonnes renvoyĂ©es par la fonction.

Lors de l'utilisation de la syntaxe ROWS FROM( ... ), si une des fonctions nĂ©cessite une liste de dĂ©finition des colonnes, il est prĂ©fĂ©rable de placer la liste de dĂ©finition des colonnes aprĂšs l'appel de la fonction dans ROWS FROM( ... ). Une liste ded dĂ©finition des colonnes peut ĂȘtre placĂ© aprĂšs la construction ROWS FROM( ... ) seulement s'il n'y a qu'une seule fonction et pas de clause WITH ORDINALITY.

Pour utiliser ORDINALITY avec une liste de définition de colonnes, vous devez utiliser la syntaxe ROWS FROM( ... ) et placer la liste de définition de colonnes dans ROWS FROM( ... ).

type_jointure

Un des éléments

  • [ INNER ] JOIN

  • LEFT [ OUTER ] JOIN

  • RIGHT [ OUTER ] JOIN

  • FULL [ OUTER ] JOIN

Pour les types de jointures INNER et OUTER, une condition de jointure doit ĂȘtre spĂ©cifiĂ©e, Ă  choisir parmi ON condition_jointure ou USING (colonne_jointure [, ...]) ou NATURAL. Voir ci-dessous pour les significations.

Une clause JOIN combine deux Ă©lĂ©ments FROM, que nous allons appelons « tables Â» par simplicitĂ© bien qu'ils puissent ĂȘtre n'importe quel Ă©lĂ©ment utilisable dans une clause FROM. Les parenthĂšses peuvent ĂȘtre utilisĂ©es pour dĂ©terminer l'ordre d'imbrication. En l'absence de parenthĂšses, les JOIN sont imbriquĂ©s de gauche Ă  droite. Dans tous les cas, JOIN est plus prioritaire que les virgules sĂ©parant les Ă©lĂ©ments FROM. Toutes les options JOIN sont une facilitĂ© d'Ă©criture car elles ne font rien que vous ne pourriez faire avec les habituels FROM et WHERE.

CROSS JOIN et INNER JOIN produisent un simple produit cartésien. Le résultat est identique à celui obtenu lorsque les deux tables sont listés au premier niveau du FROM, mais restreint par la condition de jointure (si elle existe). CROSS JOIN est équivalent à INNER JOIN ON (TRUE), c'est-à-dire qu'aucune ligne n'est supprimée par qualification. Ces types de jointure sont essentiellement une aide à la notation car ils ne font rien de plus qu'un simple FROM et WHERE.

LEFT OUTER JOIN renvoie toutes les lignes du produit cartésien qualifié (c'est-à-dire toutes les lignes combinées qui satisfont la condition de jointure), plus une copie de chaque ligne de la table de gauche pour laquelle il n'y a pas de ligne à droite qui satisfasse la condition de jointure. La ligne de gauche est étendue à la largeur complÚte de la table jointe par insertion de valeurs NULL pour les colonnes de droite. Seule la condition de la clause JOIN est utilisée pour décider des lignes qui correspondent. Les conditions externes sont appliquées aprÚs coup.

À l'inverse, RIGHT OUTER JOIN renvoie toutes les lignes jointes plus une ligne pour chaque ligne de droite sans correspondance (complĂ©tĂ©e par des NULL pour le cĂŽtĂ© gauche). C'est une simple aide Ă  la notation car il est aisĂ©ment convertible en LEFT en inversant les tables gauche et droite.

FULL OUTER JOIN renvoie toutes les lignes jointes, plus chaque ligne gauche sans correspondance (étendue par des NULL à droite), plus chaque ligne droite sans correspondance (étendue par des NULL à gauche).

ON condition_jointure

condition_jointure est une expression qui retourne une valeur de type boolean (comme une clause WHERE) qui spécifie les lignes d'une jointure devant correspondre.

USING (colonne_jointure [, ...])

Une clause de la forme USING ( a, b, ... ) est un raccourci pour ON table_gauche.a = table_droite.a AND table_gauche.b = table_droite.b .... De plus, USING implique l'affichage d'une seule paire des colonnes correspondantes dans la sortie de la jointure.

NATURAL

NATURAL est un raccourci pour une liste USING qui mentionne toutes les colonnes de mĂȘme nom dans les deux tables. USING qui mentionne toutes les colonnes de mĂȘme nom dans les deux tables. S'il n'y a pas de noms de colonnes communs, NATURAL est Ă©quivalent Ă  ON TRUE.

CROSS JOIN

CROSS JOIN est Ă©quivalent Ă  INNER JOIN ON (TRUE), c'est-Ă -dire qu'aucune ligne n'est supprimĂ©e par la qualification. Elles rĂ©alisent un produit cartĂ©sien, donc les mĂȘmes rĂ©sultats que vous obtiendriez en listant les deux tables au niveau haut d'un FROM, mais restreints Ă  la condition de jointure (s'il y en a une).

LATERAL

Le mot clé LATERAL peut précéder un élément sous-SELECT de la clause FROM. Ceci permet au sous-SELECT de faire référence aux colonnes des éléments du FROM qui apparaissent avant lui dans la liste FROM. (Sans LATERAL, chaque sous-SELECT est évalué indépendamment et donc ne peut pas faire référence à tout autre élément de la clause FROM.)

LATERAL peut aussi précéder un élément fonction dans la clause FROM mais dans ce cas, ce n'est pas requis car l'expression de la fonction peut faire référence aux éléments du FROM dans tous les cas.

Un élément LATERAL peut apparaßtre au niveau haut dans la liste FROM ou à l'intérieur d'un arbre JOIN. Dans ce dernier cas, il peut aussi faire référence à tout élément qui se trouvent à la gauche d'un JOIN qui est à sa droite.

Quand un Ă©lĂ©ment du FROM des rĂ©fĂ©rences LATERAL, l'Ă©valuation se fait ainsi : pour chaque ligne d'un Ă©lĂ©ment FROM fournissant une colonne rĂ©fĂ©rencĂ©e ou un ensemble de lignes provenant de plusieurs Ă©lĂ©ments FROM fournissant les colonnes, l'Ă©lĂ©ment LATERAL est Ă©valuĂ©e en utilisant la valeur des colonnes de cette (ou ces) ligne(s). Les lignes rĂ©sultantes sont jointes comme d'habitude avec les lignes pour lesquelles elles ont Ă©tĂ© calculĂ©es. Ceci est rĂ©pĂ©tĂ© pour chaque ligne ou chaque ensemble de lignes provenant de la table contenant les colonnes rĂ©fĂ©rencĂ©es.

Le(s) table(s) contenant les colonnes rĂ©fĂ©rencĂ©es doivent ĂȘtre jointes avec INNER ou LEFT Ă  l'Ă©lĂ©ment LATERAL. Sinon il n'y aurait pas un ensemble bien dĂ©fini de lignes Ă  partir duquel on pourrait construire chaque ensemble de lignes pour l'Ă©lĂ©ment LATERAL. Du coup, bien qu'une construction comme X RIGHT JOIN LATERAL Y est valide syntaxiquement, il n'est pas permis Ă  Y de rĂ©fĂ©rencer X.

Clause WHERE

La clause WHERE optionnelle a la forme générale

WHERE condition
    

oĂč condition est une expression dont le rĂ©sultat est de type boolean. Toute ligne qui ne satisfait pas cette condition est Ă©liminĂ©e de la sortie. Une ligne satisfait la condition si elle retourne vrai quand les valeurs rĂ©elles de la ligne sont substituĂ©es Ă  toute rĂ©fĂ©rence de variable.

Clause GROUP BY

La clause GROUP BY optionnelle a la forme générale

GROUP BY element_regroupement [, ...]
    

GROUP BY condensera en une seule ligne toutes les lignes sĂ©lectionnĂ©es partageant les mĂȘmes valeurs pour les expressions regroupĂ©es. Une expression utilisĂ©e Ă  l'intĂ©rieur d'un element_regroupement peut ĂȘtre un nom de colonne en entrĂ©e, ou le nom ou le numĂ©ro d'une colonne en sortie (Ă©lĂ©ment de la liste SELECT), ou une expression arbitraire formĂ©e Ă  partir des valeurs ou colonnes en entrĂ©e. En cas d'ambiguitĂ©, un nom GROUP BY sera interprĂ©tĂ© comme un nom de colonne en entrĂ©e plutĂŽt qu'en tant que nom de colonne en sortie.

Si une clause parmi GROUPING SETS, ROLLUP ou CUBE est prĂ©sente comme Ă©lĂ©ment de regroupement, alors la clause GROUP BY dans sa globalitĂ© dĂ©finit un certain nombre d'ensembles de regroupement indĂ©pendants. L'effet de ceci est l'Ă©quivalent de la construction d'un UNION ALL des sous-requĂȘtes pour chaque ensemble de regroupement individuel avec leur propre clause GROUP BY. Pour plus de dĂ©tails sur la gestion des ensembles de regroupement, voir Section 7.2.4.

Les fonctions d'agrĂ©gat, si utilisĂ©es, sont calculĂ©es pour toutes les lignes composant un groupe, produisant une valeur sĂ©parĂ©e pour chaque groupe. (S'il y a des fonctions d'agrĂ©gat mais pas de clause GROUP BY, la requĂȘte est traitĂ©e comme ayant un seul groupe contenant toutes les lignes sĂ©lectionnĂ©es.) L'ensemble de lignes envoyĂ©es Ă  la fonction d'agrĂ©gat peut ĂȘtre en plus filtrĂ© en ajoutant une clause FILTER lors de l'appel Ă  la fonction d'agrĂ©gat ; voir Section 4.2.7 pour plus d'informations. Quand une clause FILTER est prĂ©sente, seules les lignes correspondant au filtre sont incluses en entrĂ©e de cette fonction d'agrĂ©gat.

Quand GROUP BY est présent ou que des fonctions d'agrégat sont présentes, les expressions du SELECT ne peuvent faire référence qu'à des colonnes groupées, sauf à l'intérieur de fonctions d'agrégat, ou bien si la colonne non groupée dépend fonctionnellement des colonnes groupées. En effet, s'il en était autrement, il y aurait plus d'une valeur possible pour la colonne non groupée. Une dépendance fonctionnelle existe si les colonnes groupées (ou un sous-ensemble de ces derniÚres) sont la clé primaire de la table contenant les colonnes non groupées.

Rappelez-vous que toutes les fonctions d'agrĂ©gat sont Ă©valuĂ©es avant l'Ă©valuation des expressions « scalaires Â» dans la clause HAVING ou la liste SELECT. Ceci signifie que, par exemple, une expression CASE ne peut pas ĂȘtre utilisĂ©e pour ignorer l'Ă©valuation de la fonction d'agrĂ©gat ; voir Section 4.2.14.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©es avec GROUP BY.

Clause HAVING

La clause optionnelle HAVING a la forme générale

HAVING condition
    

oĂč condition est identique Ă  celle spĂ©cifiĂ©e pour la clause WHERE.

HAVING Ă©limine les lignes groupĂ©es qui ne satisfont pas Ă  la condition. HAVING est diffĂ©rent de WHERE : WHERE filtre les lignes individuelles avant l'application de GROUP BY alors que HAVING filtre les lignes groupĂ©es créées par GROUP BY. Chaque colonne rĂ©fĂ©rencĂ©e dans condition doit faire rĂ©fĂ©rence sans ambiguĂŻtĂ© Ă  une colonne groupĂ©e, sauf si la rĂ©fĂ©rence apparaĂźt dans une fonction d'agrĂ©gat ou que les colonnes non groupĂ©es sont fonctionnement dĂ©pendantes des colonnes groupĂ©es.

MĂȘme en l'absence de clause GROUP BY, la prĂ©sence de HAVING transforme une requĂȘte en requĂȘte groupĂ©e. Cela correspond au comportement d'une requĂȘte contenant des fonctions d'agrĂ©gats mais pas de clause GROUP BY. Les lignes sĂ©lectionnĂ©es ne forment qu'un groupe, la liste du SELECT et la clause HAVING ne peuvent donc faire rĂ©fĂ©rence qu'Ă  des colonnes Ă  l'intĂ©rieur de fonctions d'agrĂ©gats. Une telle requĂȘte ne produira qu'une seule ligne si la condition HAVING est rĂ©alisĂ©e, aucune dans le cas contraire.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©es avec GROUP BY.

Clause WINDOW

La clause optionnelle WINDOW a la forme générale

WINDOW nom_window AS ( définition_window ) [, ...]
    

oĂč nom_window est un nom qui peut ĂȘtre rĂ©fĂ©rencĂ© par des clauses OVER ou par des dĂ©finitions Window, et dĂ©finition_window est

[ nom_window_existante ]
[ PARTITION BY expression [, ...] ]
[ ORDER BY expression [ ASC | DESC | USING operateur ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ clause_frame ]
    

Si un nom_window_existante est spĂ©cifiĂ©, il doit se rĂ©fĂ©rer Ă  une entrĂ©e prĂ©cĂ©dente dans la liste WINDOW ; la nouvelle Window copie sa clause de partitionnement de cette entrĂ©e, ainsi que sa clause de tri s'il y en a. Dans ce cas, la nouvelle Window ne peut pas spĂ©cifier sa propre clause PARTITION BY, et ne peut spĂ©cifier de ORDER BY que si la Window copiĂ©e n'en a pas. La nouvelle Window utilise toujours sa propre clause frame ; la Window copiĂ©e ne doit pas possĂ©der de clause frame.

Les Ă©lĂ©ments de la liste PARTITION BY sont interprĂ©tĂ©s Ă  peu prĂšs de la mĂȘme façon que des Ă©lĂ©ments de la section intitulĂ©e « Clause GROUP BY Â», sauf qu'ils sont toujours des expressions simples et jamais le nom ou le numĂ©ro d'une colonne en sortie. Une autre diffĂ©rence est que ces expressions peuvent contenir des appels Ă  des fonctions d' agrĂ©gat, ce qui n'est pas autorisĂ© dans une clause GROUP BY classique. Ceci est autorisĂ© ici parce que le windowing se produit aprĂšs le regroupement et l' agrĂ©gation.

De façon similaire, les Ă©lĂ©ments de la liste ORDER BY sont interprĂ©tĂ©s Ă  peu prĂšs de la mĂȘme façon que les Ă©lĂ©ments d'un la section intitulĂ©e « Clause ORDER BY Â», sauf que les expressions sont toujours prises comme de simples expressions et jamais comme le nom ou le numĂ©ro d'une colonne en sortie.

La clause clause_frame optionnelle dĂ©finit la frame window pour les fonctions window qui dĂ©pendent de la frame (ce n'est pas le cas de toutes). La frame window est un ensemble de lignes liĂ©es Ă  chaque ligne de la requĂȘte (appelĂ©e la ligne courante). La clause_frame peut ĂȘtre une des clauses suivantes :

{ RANGE | ROWS | GROUPS } début_portée [ exclusion_portée ]
{ RANGE | ROWS | GROUPS } BETWEEN début_portée AND fin_portée [ exclusion_portée ]
    

oĂč dĂ©but_frame et fin_frame peuvent valoir

UNBOUNDED PRECEDING
décalage PRECEDING
CURRENT ROW
décalage FOLLOWING
UNBOUNDED FOLLOWING
    

et exclusion_portée peut valoir

EXCLUDE CURRENT ROW
EXCLUDE GROUP
EXCLUDE TIES
EXCLUDE NO OTHERS
    

Si fin_frame n'est pas prĂ©cisĂ©, il vaut par dĂ©faut CURRENT ROW. Les restrictions sont les suivantes : dĂ©but_frame ne peut pas valoir UNBOUNDED FOLLOWING, fin_frame ne peut pas valoir UNBOUNDED PRECEDING, et le choix fin_frame ne peut apparaĂźtre avant les options frame_start et frame_end que le choix dĂ©but_frame -- par exemple RANGE BETWEEN CURRENT ROW AND dĂ©calage PRECEDING n'est pas permis.

L'option de portĂ©e par dĂ©faut est RANGE UNBOUNDED PRECEDING, qui est identique Ă  RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ; cela configure la portĂ©e Ă  toutes les lignes du dĂ©but de la partition jusqu'au dernier peer de la ligne courant (une ligne que la clause ORDER BY de fenĂȘtrage considĂšre Ă©quivalente Ă  la ligne courante ; toutes les lignes sont dans ce cas s'il n'y a pas d'ORDER BY). En gĂ©nĂ©ral, UNBOUNDED PRECEDING signifie que la portĂ©e comment avec la premiĂšre ligne de la partition et, de façon similaire, UNBOUNDED FOLLOWING signifie que la portĂ©e se termine avec la derniĂšre ligne de la partition, quelque soit le mot (RANGE, ROWS or GROUPS). Dans le mode ROWS, CURRENT ROW signifie que la portĂ©e commence ou se termine avec la ligne actuelle ; mais dans les modes RANGE et GROUPS, il signifie que la portĂ©e commence ou se termine avec le premier ou le dernier Ă©quivalent de la ligne courante d'aprĂšs le tri ORDER BY. Les options offset PRECEDING et offset FOLLOWING varient en signification suivant le mode de portĂ©e. Dans le mode ROWS, offset est un entier indiquant que la portĂ©e commence ou se termine par ce nombre de lignes avant ou aprĂšs la ligne actuelle. Dans le mode GROUPS, offset est un entier indiquant que la portĂ©e commence ou se termine par ce nombre de groupes d'Ă©quivalents avant ou aprĂšs le groupe d'Ă©quivalents de la ligne courante, oĂč un groupe d'Ă©quivalents est un groupe de lignes Ă©quivalentes suivant la clause ORDER BY de fenĂȘtrage. Dans le mode RANGE, l'utilisation de l'option offset requiert qu'il y ait exactement une colonne ORDER BY dans la dĂ©finition de la fenĂȘtre. Ensuite, la portĂ©e contient ces lignes dont la valeur de la colonne de tri n'est pas infĂ©rieur de offset (pour PRECEDING) ou supĂ©rieur (pour FOLLOWING) Ă  la valeur de la colonne de tri de la ligne courante. Dans ces cas, le type de donnĂ©es de l'expression offset dĂ©pend du typ de donnĂ©es de la colonne de tri. Pour les colonnes numĂ©riques, il s'agit typiquement du mĂȘme type que la colonne de tri. Pour les colonnes date/heure, il s'agit typiquement d'un interval. Dans tous les cas, la valeur de offset doit ĂȘtre non NULL et non nĂ©gative. De plus, alors que offset n'a pas besoin d'ĂȘtre une simple constante, elle ne peut pas contenir des variables, des fonctions d'agrĂ©gat et des fonctions de fenĂȘtrage.

L'option exclusion_portĂ©e autorise les lignes autour de la ligne courante d'ĂȘtre exclues de la portĂ©e, mĂȘme si elles devraient ĂȘtre includes d'aprĂšs les options de dĂ©but et de fin de portĂ©e. EXCLUDE CURRENT ROW exclut la ligne courante de la portĂ©e. EXCLUDE GROUP exclut la ligne courante et ses Ă©quivalents de tri Ă  partir de la portĂ©e. EXCLUDE TIES exclut tout Ă©quivalent de la ligne courante Ă  partir de la portĂ©e, mais pas la ligne courante elle-mĂȘme. EXCLUDE NO OTHERS indique seulement explicitement le comportement par dĂ©faut qui est de ne pas exclure la ligne courante et ses Ă©quivalents.

Notez que le mode ROWS peut produire des rĂ©sultats inattendus si la clause ORDER BY ne trie pas les lignes de façon unique. Les modes RANGE et GROUPS sont conçus pour s'assurer que les lignes Ă©quivalents d'aprĂšs le tri ORDER BY sont traitĂ©es de la mĂȘme façon  : toutes les lignes d'un groupe d'Ă©quivalent sera inclus dans la portĂ©e ou en sera exclus.

L'utilitĂ© d'une clause WINDOW est de spĂ©cifier le comportement des fonctions window apparaissant dans la clause la section intitulĂ©e « Liste SELECT Â» ou la clause la section intitulĂ©e « Clause ORDER BY Â» de la requĂȘte. Ces fonctions peuvent rĂ©fĂ©rencer les entrĂ©es de clauses WINDOW par nom dans leurs clauses OVER. Toutefois, il n'est pas obligatoire qu'une entrĂ©e de clause WINDOW soit rĂ©fĂ©rencĂ©e quelque part ; si elle n'est pas utilisĂ©e dans la requĂȘte, elle est simplement ignorĂ©e. Il est possible d'utiliser des fonctions window sans aucune clause WINDOW puisqu'une fonction window peut spĂ©cifier sa propre dĂ©finition de window directement dans sa clause OVER. Toutefois, la clause WINDOW Ă©conomise de la saisie quand la mĂȘme dĂ©finition window est utilisĂ©e pour plus d'une fonction window.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©es avec GROUP BY.

Les fonctions window sont dĂ©crites en dĂ©tail dans Section 3.5, Section 4.2.8 et Section 7.2.5.

Liste SELECT

La liste SELECT (entre les mots clés SELECT et FROM) spécifie les expressions qui forment les lignes en sortie de l'instruction SELECT. Il se peut que les expressions fassent référence aux colonnes traitées dans la clause FROM. En fait, en général, elles le font.

Comme pour une table, chaque colonne de sortie d'un SELECT a un nom. Dans un SELECT simple, ce nom est juste utilisĂ© pour donner un titre Ă  la colonne pour l'affichage, mais quand le SELECT est une sous-requĂȘte d'une requĂȘte plus grande, le nom est vu par la grande requĂȘte comme le nom de colonne de la table virtuelle produite par la sous-requĂȘte. Pour indiquer le nom Ă  utiliser pour une colonne de sortie, Ă©crivez AS nom_de_sortie aprĂšs l'expression de la colonne. (Vous pouvez omettre AS seulement si le nom de colonne souhaitĂ© n'est pas un mot clĂ© rĂ©servĂ© par PostgreSQL (voir Annexe C). Pour vous protĂ©ger contre l'ajout futur d'un mot clĂ©, il est recommandĂ© que vous Ă©criviez toujours AS ou que vous mettiez le nom de sortie entre guillemets. Si vous n'indiquez pas de nom de colonne, un nom est choisi automatiquement par PostgreSQL. Si l'expression de la colonne est une simple rĂ©fĂ©rence Ă  une colonne alors le nom choisi est le mĂȘme que le nom de la colonne. Dans les cas plus complexes, un nom de fonction ou de type peut ĂȘtre utilisĂ©, ou le systĂšme peut opter pour un nom gĂ©nĂ©rĂ© automatiquement tel que ?column?.

Un nom de colonne de sortie peut ĂȘtre utilisĂ© pour se rĂ©fĂ©rer Ă  la valeur de la colonne dans les clauses ORDER BY et GROUP BY, mais pas dans la clauseWHERE ou HAVING ; Ă  cet endroit, vous devez Ă©crire l'expression.

* peut ĂȘtre utilisĂ©, Ă  la place d'une expression, dans la liste de sortie comme raccourci pour toutes les colonnes des lignes sĂ©lectionnĂ©es. De plus, nom_table.* peut ĂȘtre Ă©crit comme raccourci pour toutes les colonnes de cette table. Dans ces cas, il est impossible de spĂ©cifier de nouveaux noms avec AS ; les noms des colonnes de sorties seront les mĂȘme que ceux de la table.

Suivant le standard SQL, les expressions dans la liste en sortie doivent ĂȘtre calculĂ©es avant d'appliquer les clauses DISTINCT, ORDER BY et LIMIT. Ceci est Ă©videmment nĂ©cessaire lors de l'utilisation de DISTINCT car, dans le cas contraire, il est difficile de distinguer les valeurs. NĂ©anmoins, dans de nombreux cas, il est plus intĂ©ressant que les expressions en sortie soient calculĂ©es aprĂšs les clauses ORDER BY et LIMIT, tout particuliĂšrement si la liste en sortie contient des fonctions volatiles ou coĂ»teuses. Avec ce comportement, l'ordre d'Ă©valuation des fonctions est plus intuitive et il n'y aurait pas d'Ă©valuations correspondant aux lignes n'apparaissant pas en sortie. PostgreSQL Ă©valuera rĂ©ellement les expressions en sortie aprĂšs le tri et la limite, si tant est que ces expressions ne sont pas rĂ©fĂ©rencĂ©es dans les clauses DISTINCT, ORDER BY et GROUP BY. (En contre-exemple, SELECT f(x) FROM tab ORDER BY 1 doit forcĂ©ment Ă©valuer f(x) avant de rĂ©aliser le tri.) Les expressions en sortie contenant des fonctions renvoyant plusieurs lignes sont rĂ©ellement Ă©valuĂ©es aprĂšs le tri et avant l'application de la limite, pour que LIMIT permette d'Ă©viter l'exĂ©cution inutile de la fonction.

Note

Les versions de PostgreSQL antérieures à la 9.6 ne fournissaient pas de garantie sur la durée de l'évaluation des expressions en sortie par rapport aux tris et aux limites. Cela dépendait de la forme du plan d'exécution sélectionné.

DISTINCT Clause

Si SELECT DISTINCT est spécifié, toutes les lignes en double sont supprimées de l'ensemble de résultats (une ligne est conservée pour chaque groupe de doublons). SELECT ALL spécifie le contraire : toutes les lignes sont conservées. C'est l'option par défaut.

SELECT DISTINCT ON ( expression [, ...] ) conserve seulement la premiĂšre ligne de chaque ensemble de lignes pour lesquelles le rĂ©sultat de l'expression est identique. Les expressions DISTINCT ON expressions sont interprĂ©tĂ©es avec les mĂȘmes rĂšgles que pour ORDER BY (voir ci-dessous). Notez que la « premiĂšre ligne Â» de chaque ensemble est imprĂ©visible, Ă  moins que la clause ORDER BY ne soit utilisĂ©e, assurant ainsi que la ligne souhaitĂ©e apparaisse en premier. Par exemple :

SELECT DISTINCT ON (lieu) lieu, heure, rapport
    FROM rapport_météo
    ORDER BY lieu, heure DESC;
    

renvoie le rapport météo le plus récent de chaque endroit. Mais si nous n'avions pas utilisé ORDER BY afin de forcer le tri du temps dans le sens descendant des temps pour chaque endroit, nous aurions récupéré, pour chaque lieu, n'importe quel bulletin de ce lieu.

La (ou les) expression(s) DISTINCT ON doivent correspondre à l'expression (ou aux expressions) ORDER BY la(les) plus à gauche. La clause ORDER BY contient habituellement des expressions supplémentaires qui déterminent l'ordre des lignes au sein de chaque groupe DISTINCT ON.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©es avec DISTINCT.

Clause UNION

La clause UNION a la forme gĂ©nĂ©rale :

instruction_select UNION [ ALL | DISTINCT ] instruction_select
    

instruction_select est une instruction SELECT sans clause ORDER BY, LIMIT, FOR SHARE ou FOR UPDATE. (ORDER BY et LIMIT peuvent ĂȘtre attachĂ©s Ă  une sous-expression si elle est entourĂ©e de parenthĂšses. Sans parenthĂšses, ces clauses s'appliquent au rĂ©sultat de l'UNION, non Ă  l'expression Ă  sa droite.)

L'opĂ©rateur UNION calcule l'union ensembliste des lignes renvoyĂ©es par les instructions SELECT impliquĂ©es. Une ligne est dans l'union de deux ensembles de rĂ©sultats si elle apparaĂźt dans au moins un des ensembles. Les deux instructions SELECT qui reprĂ©sentent les opĂ©randes directes de l'UNION doivent produire le mĂȘme nombre de colonnes et les colonnes correspondantes doivent ĂȘtre d'un type de donnĂ©es compatible.

Sauf lorsque l'option ALL est spĂ©cifiĂ©e, il n'y a pas de doublons dans le rĂ©sultat de UNION. ALL empĂȘche l'Ă©limination des lignes dupliquĂ©es. UNION ALL est donc significativement plus rapide qu'UNION, et sera prĂ©fĂ©rĂ©. DISTINCT peut Ă©ventuellement ĂȘtre ajoutĂ© pour prĂ©ciser explicitement le comportement par dĂ©faut : l'Ă©limination des lignes en double.

Si une instruction SELECT contient plusieurs opérateurs UNION, ils sont évalués de gauche à droite, sauf si l'utilisation de parenthÚses impose un comportement différent.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©s pour un rĂ©sultat d'UNION ou pour toute entrĂ©e d'un UNION.

Clause INTERSECT

La clause INTERSECT a la forme gĂ©nĂ©rale :

instruction_select INTERSECT [ ALL | DISTINCT ] instruction_select
    

instruction_select est une instruction SELECT sans clause ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE ou FOR KEY SHARE.

L'opérateur INTERSECT calcule l'intersection des lignes renvoyées par les instructions SELECT impliquées. Une ligne est dans l'intersection des deux ensembles de résultats si elle apparaßt dans chacun des deux ensembles.

Le rĂ©sultat d'INTERSECT ne contient aucune ligne dupliquĂ©e sauf si l'option ALL est spĂ©cifiĂ©e. Dans ce cas, une ligne dupliquĂ©e m fois dans la table gauche et n fois dans la table droite apparaĂźt min(m,n) fois dans l'ensemble de rĂ©sultats. DISTINCT peut Ă©ventuellement ĂȘtre ajoutĂ© pour prĂ©ciser explicitement le comportement par dĂ©faut : l'Ă©limination des lignes en double.

Si une instruction SELECT contient plusieurs opérateurs INTERSECT, ils sont évalués de gauche à droite, sauf si l'utilisation de parenthÚses impose un comportement différent. INTERSECT a une priorité supérieur à celle d'UNION. C'est-à-dire que A UNION B INTERSECT C est lu comme A UNION (B INTERSECT C).

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©s pour un rĂ©sultat d'INTERSECT ou pour une entrĂ©e d'INTERSECT.

Clause EXCEPT

La clause EXCEPT a la forme gĂ©nĂ©rale :

instruction_select EXCEPT [ ALL | DISTINCT ] instruction_select
    

instruction_select est une instruction SELECT sans clause ORDER BY, LIMIT, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE ou FOR KEY SHARE.

L'opérateur EXCEPT calcule l'ensemble de lignes qui appartiennent au résultat de l'instruction SELECT de gauche mais pas à celui de droite.

Le rĂ©sultat d'EXCEPT ne contient aucune ligne dupliquĂ©e sauf si l'option ALL est spĂ©cifiĂ©e. Dans ce cas, une ligne dupliquĂ©e m fois dans la table gauche et n fois dans la table droite apparaĂźt max(m-n,0) fois dans l'ensemble de rĂ©sultats. DISTINCT peut Ă©ventuellement ĂȘtre ajoutĂ© pour prĂ©ciser explicitement le comportement par dĂ©faut : l'Ă©limination des lignes en double.

Si une instruction SELECT contient plusieurs opĂ©rateurs EXCEPT, ils sont Ă©valuĂ©s de gauche Ă  droite, sauf si l'utilisation de parenthĂšses impose un comportement diffĂ©rent. EXCEPT a la mĂȘme prioritĂ© qu'UNION.

Actuellement, FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE et FOR KEY SHARE ne peuvent pas ĂȘtre spĂ©cifiĂ©s dans un rĂ©sultat EXCEPT ou pour une entrĂ©e d'un EXCEPT.

Clause ORDER BY

La clause optionnelle ORDER BY a la forme gĂ©nĂ©rale :

ORDER BY expression [ ASC | DESC | USING opérateur ] [ NULLS { FIRST | LAST } ] [, ...]
    

La clause ORDER BY impose le tri des lignes de résultat suivant les expressions spécifiées. Si deux lignes sont identiques suivant l'expression la plus à gauche, elles sont comparées avec l'expression suivante et ainsi de suite. Si elles sont identiques pour toutes les expressions de tri, elles sont renvoyées dans un ordre dépendant de l'implantation.

Chaque expression peut ĂȘtre le nom ou le numĂ©ro ordinal d'une colonne en sortie (Ă©lĂ©ment de la liste SELECT). Elle peut aussi ĂȘtre une expression arbitraire formĂ©e Ă  partir de valeurs des colonnes.

Le numéro ordinal fait référence à la position ordinale (de gauche à droite) de la colonne de résultat. Cette fonctionnalité permet de définir un ordre sur la base d'une colonne dont le nom n'est pas unique. Ce n'est pas particuliÚrement nécessaire parce qu'il est toujours possible d'affecter un nom à une colonne de résultat avec la clause AS.

Il est aussi possible d'utiliser des expressions quelconques dans la clause ORDER BY, ce qui inclut des colonnes qui n'apparaissent pas dans la liste rĂ©sultat du SELECT. Ainsi, l'instruction suivante est valide :

SELECT nom FROM distributeurs ORDER BY code;
    

Il y a toutefois une limitation à cette fonctionnalité. La clause ORDER BY qui s'applique au résultat d'une clause UNION, INTERSECT ou EXCEPT ne peut spécifier qu'un nom ou numéro de colonne en sortie, pas une expression.

Si une expression ORDER BY est un nom qui correspond Ă  la fois Ă  celui d'une colonne rĂ©sultat et Ă  celui d'une colonne en entrĂ©e, ORDER BY l'interprĂšte comme le nom de la colonne rĂ©sultat. Ce comportement est Ă  l'opposĂ© de celui de GROUP BY dans la mĂȘme situation. Cette incohĂ©rence est imposĂ©e par la compatibilitĂ© avec le standard SQL.

Un mot clĂ© ASC (ascendant) ou DESC (descendant) peut ĂȘtre ajoutĂ© aprĂšs toute expression de la clause ORDER BY. ASC est la valeur utilisĂ©e par dĂ©faut. Un nom d'opĂ©rateur d'ordre spĂ©cifique peut Ă©galement ĂȘtre fourni dans la clause USING. Un opĂ©rateur de tri doit ĂȘtre un membre plus-petit-que ou plus-grand-que de certaines familles d'opĂ©rateur B-tree. ASC est habituellement Ă©quivalent Ă  USING < et DESC Ă  USING >. Le crĂ©ateur d'un type de donnĂ©es utilisateur peut dĂ©finir Ă  sa guise le tri par dĂ©faut qui peut alors correspondre Ă  des opĂ©rateurs de nom diffĂ©rent.

Si NULLS LAST est indiquĂ©, les valeurs NULL sont listĂ©es aprĂšs toutes les valeurs non NULL  si NULLS FIRST est indiquĂ©, les valeurs NULL apparaissent avant toutes les valeurs non NULL. Si aucune des deux n'est prĂ©sente, le comportement par dĂ©faut est NULLS LAST quand ASC est utilisĂ© (de façon explicite ou non) et NULLS FIRST quand DESC est utilisĂ© (donc la valeur par dĂ©faut est d'agir comme si les NULL Ă©taient plus grands que les non NULL). Quand USING est indiquĂ©, le tri des NULL par dĂ©faut dĂ©pend du fait que l'opĂ©rateur est un plus-petit-que ou un plus-grand-que.

Notez que les options de tri s'appliquent seulement Ă  l'expression qu'elles suivent. Par exemple, ORDER BY x, y DESC ne signifie pas la mĂȘme chose que ORDER BY x DESC, y DESC.

Les chaĂźnes de caractĂšres sont triĂ©es suivant le collationnement qui s'applique Ă  la colonne triĂ©e. Ce collationnement est surchargeable si nĂ©cessaire en ajoutant une clause COLLATE dans l'expression, par exemple ORDER BY mycolumn COLLATE "en_US". Pour plus d'informations, voir Section 4.2.10 et Section 23.2.

Clause LIMIT

La clause LIMIT est constituĂ©e de deux sous-clauses indĂ©pendantes :

LIMIT { nombre | ALL }
OFFSET début
    

nombre spécifie le nombre maximum de lignes à renvoyer alors que début spécifie le nombre de lignes à passer avant de commencer à renvoyer des lignes. Lorsque les deux clauses sont spécifiées, début lignes sont passées avant de commencer à compter les nombre lignes à renvoyer.

Si l'expression de compte est évaluée à NULL, il est traité comme LIMIT ALL, c'est-à-dire sans limite. Si début est évalué à NULL, il est traité comme OFFSET 0.

SQL:2008 a introduit une sytaxe diffĂ©rente pour obtenir le mĂȘme rĂ©sultat. PostgreSQL supporte aussi cette syntaxe.

OFFSET début { ROW | ROWS }
FETCH { FIRST | NEXT } [ compte ] { ROW | ROWS } ONLY
    

Avec cette syntaxe, le standard SQL exige que la valeur de start ou count soit une constante litĂ©rale, un paramĂštre ou un nom de variable. PostgreSQL propose en extension l'utilisation d'autres expressions. Ces derniĂšres devront gĂ©nĂ©ralement ĂȘtre entre parenthĂšses pour Ă©viter toute ambiguĂŻtĂ©. Si compte est omis dans une clause FETCH, il vaut 1 par dĂ©faut. ROW et ROWS ainsi que FIRST et NEXT sont des mots qui n'influencent pas les effets de ces clauses. D'aprĂšs le standard, la clause OFFSET doit venir avant la clause FETCH si les deux sont prĂ©sentes ; PostgreSQL est plus laxiste et autorise un ordre diffĂ©rent.

Avec LIMIT, utiliser la clause ORDER BY permet de contraindre l'ordre des lignes de résultat. Dans le cas contraire, le sous-ensemble obtenu n'est pas prévisible -- rien ne permet de savoir à quel ordre correspondent les lignes retournées. Celui-ci ne sera pas connu tant qu'ORDER BY n'aura pas été précisé.

Lors de la gĂ©nĂ©ration d'un plan de requĂȘte, le planificateur tient compte de LIMIT. Le risque est donc grand d'obtenir des plans qui diffĂšrent (ordres des lignes diffĂ©rents) suivant les valeurs utilisĂ©es pour LIMIT et OFFSET. Ainsi, sĂ©lectionner des sous-ensembles diffĂ©rents d'un rĂ©sultat Ă  partir de valeurs diffĂ©rentes de LIMIT/OFFSET aboutit Ă  des rĂ©sultats incohĂ©rents Ă  moins d'avoir figĂ© l'ordre des lignes Ă  l'aide de la clause ORDER BY. Ce n'est pas un bogue, mais une consĂ©quence du fait que SQL n'assure pas l'ordre de prĂ©sentation des rĂ©sultats sans utilisation d'une clause ORDER BY.

Il est mĂȘme possible pour des exĂ©cutions rĂ©pĂ©tĂ©es de la mĂȘme requĂȘte LIMIT de renvoyer diffĂ©rents sous-ensembles des lignes d'une table s'il n'y a pas de clause ORDER BY pour forcer la sĂ©lection d'un sous-ensemble dĂ©terministe. Encore une fois, ce n'est pas un bogue ; le dĂ©terminisme des rĂ©sultats n'est tout simplement pas garanti dans un tel cas.

Clause de verrouillage

FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE et FOR KEY SHARE sont des clauses de verrouillage. Elles affectent la façon dont SELECT verrouille les lignes au moment de leur obtention sur la table.

La clause de verrouillage a la forme suivante :

FOR force_verrou [ OF nom_table [, ...] ] [ NOWAIT | SKIP LOCKED ]
    

oĂč force_verrou fait partie de :

UPDATE
NO KEY UPDATE
SHARE
KEY SHARE
    

Pour plus d'informations sur chaque mode de verrouillage au niveau ligne, voir Section 13.3.2.

Pour Ă©viter que l'opĂ©ration attende la validation d'autres transactions, utilisez soit l'option NOWAIT soit l'option SKIP LOCKED. Avec NOWAIT, l'instruction renvoie une erreur, plutĂŽt que de rester en attente, si une ligne sĂ©lectionnĂ©e ne peut pas ĂȘtre immĂ©diatement verrouillĂ©e. Avec SKIP LOCKED, toute ligne sĂ©lectionnĂ©e qui ne peut pas ĂȘtre immĂ©diatement verrouillĂ©e est ignorĂ©e. Ignorer les lignes verrouillĂ©es fournit une vue incohĂ©rente des donnĂ©es, donc ce n'est pas acceptable dans un cadre gĂ©nĂ©ral, mais ça peut ĂȘtre utilisĂ© pour Ă©viter les contentions de verrou lorsque plusieurs consommateurs cherchent Ă  accĂ©der Ă  une table de style queue. Notez que NOWAIT et SKIP LOCKED s'appliquent seulement au(x) verrou(x) niveau ligne -- le verrou niveau table ROW SHARE est toujours pris de façon ordinaire (voir Chapitre 13). L'option NOWAIT de LOCK peut toujours ĂȘtre utilisĂ©e pour acquĂ©rir le verrou niveau table sans attendre.

Si des tables particuliĂšres sont nommĂ©es dans une clause de verrouillage, alors seules les lignes provenant de ces tables sont verrouillĂ©es ; toute autre table utilisĂ©e dans le SELECT est simplement lue. Une clause de verrouillage sans liste de tables affecte toutes les tables utilisĂ©es dans l'instruction. Si une clause de verrouillage est appliquĂ©e Ă  une vue ou Ă  une sous-requĂȘte, cela affecte toutes les tables utilisĂ©es dans la vue ou la sous-requĂȘte. NĂ©anmoins, ces clauses ne s'appliquent pas aux requĂȘtes WITH rĂ©fĂ©rencĂ©es par la clĂ© primaire. Si vous voulez qu'un verrouillage de lignes intervienne dans une requĂȘte WITH, spĂ©cifiez une clause de verrouillage Ă  l'intĂ©rieur de la requĂȘte WITH.

Plusieurs clauses de verrouillage peuvent ĂȘtre donnĂ©es si il est nĂ©cessaire de spĂ©cifier diffĂ©rents comportements de verrouillage pour diffĂ©rentes tables. Si la mĂȘme table est mentionnĂ© (ou affectĂ©e implicitement) par plus d'une clause de verrouillage, alors elle est traitĂ©e comme la clause la plus forte. De façon similaire, une table est traitĂ©e avec NOWAIT si c'est spĂ©cifiĂ©e sur au moins une des clauses qui l'affectent. Sinon, il est traitĂ© comme SKIP LOCKED si c'est indiquĂ© dans une des clauses qui l'affectent.

Les clauses de verrouillage nĂ©cessitent que chaque ligne retournĂ©e soit clairement identifiable par une ligne individuelle d'une table ; ces options ne peuvent, par exemple, pas ĂȘtre utilisĂ©es avec des fonctions d'agrĂ©gats.

Quand une clause de verrouillage apparaissent au niveau le plus Ă©levĂ© d'une requĂȘte SELECT, les lignes verrouillĂ©es sont exactement celles qui sont renvoyĂ©es par la requĂȘte ; dans le cas d'une requĂȘte avec jointure, les lignes verrouillĂ©es sont celles qui contribuent aux lignes jointes renvoyĂ©es. De plus, les lignes qui ont satisfait aux conditions de la requĂȘte au moment de la prise de son instantanĂ© sont verrouillĂ©es, bien qu'elles ne seront pas retournĂ©es si elles ont Ă©tĂ© modifiĂ©es aprĂšs la prise du snapshot et ne satisfont plus les conditions de la requĂȘte. Si LIMIT est utilisĂ©, le verrouillage cesse une fois que suffisamment de lignes ont Ă©tĂ© renvoyĂ©es pour satisfaire la limite (mais notez que les lignes ignorĂ©es Ă  cause de la clause OFFSET seront verrouillĂ©es). De la mĂȘme maniĂšre, si une clause de verrouillage est utilisĂ© pour la requĂȘte d'un curseur, seules les lignes rĂ©ellement rĂ©cupĂ©rĂ©es ou parcourues par le curseur seront verrouillĂ©es.

Si une clause de verrouillage apparait dans un sous-SELECT, les lignes verrouillĂ©es sont celles renvoyĂ©es par la sous-requĂȘte Ă  la requĂȘte externe. Cela peut concerner moins de lignes que l'Ă©tude de la sous-requĂȘte seule pourrait faire penser, parce que les conditions de la requĂȘte externe peuvent ĂȘtre utilisĂ©es pour optimiser l'exĂ©cution de la sous-requĂȘte. Par exemple,

SELECT * FROM (SELECT * FROM mytable FOR UPDATE) ss WHERE col1 = 5;
    

verrouillera uniquement le lignes pour lesquelles col1 = 5, mĂȘme si cette condition n'est pas Ă©crite dans la sous-requĂȘte.

Les anciennes versions Ă©chouaient Ă  prĂ©server un verrou qui est mis Ă  jour par un point de sauvegarde ultĂ©rieur. Par exemple, ce code :

BEGIN;
SELECT * FROM ma_table WHERE cle = 1 FOR UPDATE;
SAVEPOINT s;
UPDATE ma_table SET ... WHERE cle = 1;
ROLLBACK TO s;
    

va échouer à conserver le verrou FOR UPDATE aprÚs la commande ROLLBACK TO. Ceci a été corrigé en 9.3.

Attention

Il est possible qu'une commande SELECT exĂ©cutĂ©e au niveau d'isolation READ COMMITTED et utilisant ORDER BY et une clause de verrouillage renvoie les lignes dans le dĂ©sordre. C'est possible car l' ORDER BY est appliquĂ© en premier. La commande trie le rĂ©sultat, mais peut alors ĂȘtre bloquĂ©e le temps d'obtenir un verrou sur une ou plusieurs des lignes. Une fois que le SELECT est dĂ©bloquĂ©, des valeurs sur la colonne qui sert Ă  ordonner peuvent avoir Ă©tĂ© modifiĂ©es, ce qui entraĂźne ces lignes apparaissant dans le dĂ©sordre (bien qu'elles soient dans l'ordre par rapport aux valeurs d'origine de ces colonnes). Ceci peut ĂȘtre contournĂ© si besoin en plaçant la clause FOR UPDATE/SHARE dans une sous-requĂȘte, par exemple

SELECT * FROM (SELECT * FROM matable FOR UPDATE) ss ORDER BY column1;
     

Notez que cela entraßne le verrouillage de toutes les lignes de matable, alors que FOR UPDATE au niveau supérieur verrouillerait seulement les lignes réellement renvoyées. Cela peut causer une différence de performance significative, en particulier si l' ORDER BY est combiné avec LIMIT ou d'autres restrictions. Cette technique est donc recommandée uniquement si vous vous attendez à des mises à jour concurrentes sur les colonnes servant à l'ordonnancement et qu'un résultat strictement ordonné est requis.

Au niveau d'isolation de transactions REPEATABLE READ et SERIALIZABLE, cela causera une erreur de sérialisation (avec un SQLSTATE valant '40001'), donc il n'est pas possible de recevoir des lignes non triées avec ces niveaux d'isolation.

Commande TABLE

La commande

TABLE nom
    

est équivalente à

SELECT * FROM nom
    

Elle peut ĂȘtre utilisĂ©e comme commande principale d'une requĂȘte, ou bien comme une variante syntaxique permettant de gagner de la place dans des parties de requĂȘtes complexes. Seuls les clauses de verrou de WITH, UNION, INTERSECT, EXCEPT, ORDER BY, LIMIT, OFFSET, FETCH et FOR peuvent ĂȘtre utilisĂ©es avec TABLE ; la clause WHERE et toute forme d'agrĂ©gation ne peuvent pas ĂȘtre utilisĂ©es.

Exemples

Joindre la table films avec la table distributeurs :

SELECT f.titre, f.did, d.nom, f.date_prod, f.genre
    FROM distributeurs d JOIN films f USING (did);

       titre       | did |     nom      | date_prod  |   genre
-------------------+-----+--------------+------------+------------
 The Third Man     | 101 | British Lion | 1949-12-23 | Drame
 The African Queen | 101 | British Lion | 1951-08-11 | Romantique
 ...
   

Additionner la colonne longueur de tous les films, grouper les rĂ©sultats par genre :

SELECT genre, sum(longueur) AS total FROM films GROUP BY genre;

   genre    | total
------------+-------
 Action     | 07:34
 Comédie    | 02:58
 Drame      | 14:28
 Musical    | 06:42
 Romantique | 04:38
   

Additionner la colonne longueur de tous les films, grouper les rĂ©sultats par genre et afficher les groupes dont les totaux font moins de cinq heures :

SELECT genre, sum(longueur) AS total
    FROM films
    GROUP BY genre
    HAVING sum(longueur) < interval '5 hours';

   genre    | total
------------+-------
 Comedie    | 02:58
 Romantique | 04:38
   

Les deux exemples suivants reprĂ©sentent des façons identiques de trier les rĂ©sultats individuels en fonction du contenu de la deuxiĂšme colonne (nom) :

SELECT * FROM distributeurs ORDER BY nom;
SELECT * FROM distributeurs ORDER BY 2;

 did |       nom
-----+------------------
 109 | 20th Century Fox
 110 | Bavaria Atelier
 101 | British Lion
 107 | Columbia
 102 | Jean Luc Godard
 113 | Luso films
 104 | Mosfilm
 103 | Paramount
 106 | Toho
 105 | United Artists
 111 | Walt Disney
 112 | Warner Bros.
 108 | Westward
   

L'exemple suivant présente l'union des tables distributeurs et acteurs, restreignant les résultats à ceux de chaque table dont la premiÚre lettre est un W. Le mot clé ALL est omis, ce qui permet de n'afficher que les lignes distinctes.

distributeurs:               acteurs:
 did |     nom               id |     nom
-----+--------------        ----+----------------
 108 | Westward               1 | Woody Allen
 111 | Walt Disney            2 | Warren Beatty
 112 | Warner Bros.           3 | Walter Matthau
 ...                         ...

SELECT distributeurs.nom
    FROM distributeurs
    WHERE distributeurs.nom LIKE 'W%'
UNION
SELECT actors.nom
    FROM acteurs
    WHERE acteurs.nom LIKE 'W%';

      nom
----------------
 Walt Disney
 Walter Matthau
 Warner Bros.
 Warren Beatty
 Westward
 Woody Allen
   

L'exemple suivant prĂ©sente l'utilisation d'une fonction dans la clause FROM, avec et sans liste de dĂ©finition de colonnes :

CREATE FUNCTION distributeurs(int) RETURNS SETOF distributeurs AS $$
    SELECT * FROM distributeurs WHERE did = $1;
$$ LANGUAGE SQL;

SELECT * FROM distributeurs(111);
 did |    name
-----+-------------
 111 | Walt Disney

CREATE FUNCTION distributeurs_2(int) RETURNS SETOF record AS $$
    SELECT * FROM distributeurs WHERE did = $1;
$$ LANGUAGE SQL;

SELECT * FROM distributeurs_2(111) AS (f1 int, f2 text);
 f1  |     f2
-----+-------------
 111 | Walt Disney
   

Voici un exemple d'une fonction avec la colonne ordinality :

SELECT * FROM unnest(ARRAY['a','b','c','d','e','f']) WITH ORDINALITY;
 unnest | ordinality
--------+----------
 a      |        1
 b      |        2
 c      |        3
 d      |        4
 e      |        5
 f      |        6
(6 rows)
   

Cet exemple montre comment utiliser une clause WITH simple:

WITH t AS (
    SELECT random() as x FROM generate_series(1, 3)
  )
SELECT * FROM t
UNION ALL
SELECT * FROM t;

         x
--------------------
  0.534150459803641
  0.520092216785997
 0.0735620250925422
  0.534150459803641
  0.520092216785997
 0.0735620250925422
   

Notez que la requĂȘte WITH n'a Ă©tĂ© Ă©valuĂ©e qu'une seule fois, ce qui fait qu'on a deux jeux contenant les mĂȘmes trois valeurs.

Cet exemple utilise WITH RECURSIVE pour trouver tous les subordonnĂ©s (directs ou indirects) de l'employĂ©e Marie, et leur niveau de subordination, Ă  partir d'une table qui ne donne que les subordonnĂ©s directs :

WITH RECURSIVE recursion_employes(distance, nom_employe, nom_manager) AS (
    SELECT 1, nom_employe, nom_manager
    FROM employe
    WHERE nom_manager = 'Marie'
  UNION ALL
    SELECT er.distance + 1, e.nom_employe, e.nom_manager
    FROM recursion_employes er, employe e
    WHERE er.nom_employe = e.nom_manager
  )
SELECT distance, nom_employe FROM recursion_employes;
   

Notez la forme typique des requĂȘtes rĂ©cursives : une condition initiale, suivie par UNION, suivis par la partie rĂ©cursive de la requĂȘte. Assurez-vous que la partie rĂ©cursive de la requĂȘte finira par ne plus retourner d'enregistrement, sinon la requĂȘte bouclera indĂ©finiment (Voir Section 7.8 pour plus d'exemples).

Cet exemple utilise LATERAL pour appliquer une fonction renvoyant des lignes, recupere_nom_produits(), pour chaque ligne de la table manufacturiers :

SELECT m.nom AS mnom, pnom
FROM manufacturiers m, LATERAL recupere_nom_produits(m.id) pnom;
   

Les manufacturiers qui n'ont pas encore de produits n'apparaĂźtront pas dans le rĂ©sultat car la jointure est interne. Si vous voulons inclure les noms de ces manufacturiers, la requĂȘte doit ĂȘtre Ă©crite ainsi :

SELECT m.name AS mnom, pnom
FROM manufacturiers m LEFT JOIN LATERAL recupere_nom_produits(m.id) pnom ON true;
   

Compatibilité

L'instruction SELECT est évidemment compatible avec le standard SQL. Mais il y a des extensions et quelques fonctionnalités manquantes.

Clauses FROM omises

PostgreSQL autorise l'omission de la clause FROM. Cela permet par exemple de calculer le rĂ©sultat d'expressions simples :

SELECT 2+2;

 ?column?
----------
        4
    

D'autres bases de données SQL interdisent ce comportement, sauf à introduire une table virtuelle d'une seule ligne sur laquelle exécuter la commande SELECT.

S'il n'y a pas de clause FROM, la requĂȘte ne peut pas rĂ©fĂ©rencer les tables de la base de donnĂ©es. La requĂȘte suivante est, ainsi, invalide :

SELECT distributors.* WHERE distributors.name = 'Westward';
    

Les versions antĂ©rieures Ă  PostgreSQL 8.1 acceptaient les requĂȘtes de cette forme en ajoutant une entrĂ©e implicite Ă  la clause FROM pour chaque table rĂ©fĂ©rencĂ©e. Ce n'est plus autorisĂ©.

Listes SELECT vides

La liste des expressions en sortie aprĂšs SELECT peut ĂȘtre vide, produisant ainsi une table de rĂ©sultats Ă  zĂ©ro colonne. Ceci n'est pas une syntaxe valide suivant le standard SQL. PostgreSQL l'autorise pour ĂȘtre cohĂ©rent avec le fait qu'il accepte des tables Ă  zĂ©ro colonne. NĂ©anmoins, une liste vide n'est pas autorisĂ© quand un DISTINCT est utilisĂ©.

Omettre le mot clé AS

Dans le standard SQL, le mot clĂ© AS peut ĂȘtre omis devant une colonne de sortie Ă  partir du moment oĂč le nouveau nom de colonne est un nom valide de colonne (c'est-Ă -dire, diffĂ©rent d'un mot clĂ© rĂ©servĂ©). PostgreSQL est lĂ©gĂšrement plus restrictif : AS est nĂ©cessaire si le nouveau nom de colonne est un mot clĂ© quel qu'il soit, rĂ©servĂ© ou non. Il est recommandĂ© d'utiliser AS ou des colonnes de sortie entourĂ©es de guillemets, pour Ă©viter tout risque de conflit en cas d'ajout futur de mot clĂ©.

Dans les éléments de FROM, le standard et PostgreSQL permettent que AS soit omis avant un alias qui n'est pas un mot clé réservé. Mais c'est peu pratique pour les noms de colonnes, à causes d'ambiguïtés syntaxiques.

ONLY et l'héritage

Le standard SQL impose des parenthÚses autour du nom de table aprÚs la clause ONLY, comme dans SELECT * FROM ONLY (tab1), ONLY (tab2) WHERE .... PostgreSQL considÚre les parenthÚses comme étant optionnelles.

PostgreSQL autorise une * en fin pour indiquer explicitement le comportement opposé de la clause ONLY (donc inclure les tables filles). Le standard ne le permet pas.

(Ces points s'appliquent de la mĂȘme façon Ă  toutes les commandes SQL supportant l'option ONLY.)

Restrictions de la clause TABLESAMPLE

La clause TABLESAMPLE est actuellement seulement acceptĂ©e pour les tables standards et les vues matĂ©rialisĂ©es. D'aprĂšs le standard SQL, il devrait ĂȘtre possible de l'appliquer Ă  tout Ă©lĂ©ment faisant partie de la clause FROM.

Appels de fonction dans la clause FROM

PostgreSQL autorise un appel de fonction dans la liste FROM. Pour le standard SQL, il serait nĂ©cessaire de placer cet appel de fonction dans un sous-SELECT ; autrement dit, la syntaxe FROM fonc(...) alias est Ă  peu prĂšs Ă©quivalente Ă  FROM LATERAL (SELECT fonc(...)) alias. Notez que LATERAL est considĂ©rĂ© comme Ă©tant implicite ; ceci est dĂ» au fait que le standard rĂ©clame la sĂ©mantique de LATERAL pour un Ă©lĂ©ment UNNEST() dans la clause FROM. PostgreSQL traite UNNEST() de la mĂȘme façon que les autres fonctions renvoyant des lignes.

Espace logique disponible pour GROUP BY et ORDER BY

Dans le standard SQL-92, une clause ORDER BY ne peut utiliser que les noms ou numéros des colonnes en sortie, une clause GROUP BY que des expressions fondées sur les noms de colonnes en entrée. PostgreSQL va plus loin, puisqu'il autorise chacune de ces clauses à utiliser également l'autre possibilité. En cas d'ambiguïté, c'est l'interprétation du standard qui prévaut. PostgreSQL autorise aussi l'utilisation d'expressions quelconques dans les deux clauses. Les noms apparaissant dans ces expressions sont toujours considérés comme nom de colonne en entrée, pas en tant que nom de colonne du résultat.

SQL:1999 et suivant utilisent une définition légÚrement différente, pas totalement compatible avec le SQL-92. Néanmoins, dans la plupart des cas, PostgreSQL interprÚte une expression ORDER BY ou GROUP BY en suivant la norme SQL:1999.

Dépendances fonctionnelles

PostgreSQL reconnaĂźt les dĂ©pendances fonctionnelles (qui permettent que les nom des colonnes ne soient pas dans le GROUP BY) seulement lorsqu'une clĂ© primaire est prĂ©sente dans la liste du GROUP BY. Le standard SQL spĂ©cifie des configurations supplĂ©mentaires qui doivent ĂȘtre reconnues.

LIMIT et OFFSET

Les clauses LIMIT et OFFSET sont une syntaxe spĂ©cifique Ă  PostgreSQL, aussi utilisĂ©e dans MySQL. La norme SQL:2008 a introduit les clauses OFFSET ... FETCH {FIRST|NEXT}... pour la mĂȘme fonctionnalitĂ©, comme montrĂ© plus haut dans la section intitulĂ©e « Clause LIMIT Â». Cette syntaxe est aussi utilisĂ©e par IBM DB2. (Les applications Ă©crites pour Oracle contournent frĂ©quemment le problĂšme par l'utilisation de la colonne auto-gĂ©nĂ©rĂ©e rownum pour obtenir les effets de ces clauses, qui n'est pas disponible sous PostgreSQL).

FOR NO KEY UPDATE, FOR UPDATE, FOR SHARE, FOR KEY SHARE

Bien que FOR UPDATE soit prĂ©sent dans le standard SQL, le standard ne l'autorise que comme une option de DECLARE CURSOR. PostgreSQL l'autorise dans toute requĂȘte SELECT et dans toute sous-requĂȘte SELECT, mais c'est une extension. Les variantes FOR NO KEY UPDATE, FOR SHARE et FOR KEY SHARE, ainsi que NOWAIT et SKIP LOCKED, n'apparaissent pas dans le standard.

Ordre de modification de données dans un WITH

PostgreSQL permet que les clauses INSERT, UPDATE, et DELETE soient utilisĂ©es comme requĂȘtes WITH. Ceci n'est pas prĂ©sent dans le standard SQL.

Clauses non standard

La clause DISTINCT ON est une extension du standard SQL.

ROWS FROM( ... ) est une extension du standard SQL.

Les options MATERIALIZED et NOT MATERIALIZED de la clause WITH sont des extensions au standard SQL.