Documentation PostgreSQL 14.22 » Référence » Commandes SQL » SELECT

Précédent | Niveau supérieur | Suivant
SECURITY LABEL | Sommaire | SELECT INTO

## 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 [ ALL | DISTINCT ] 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 | WITH TIES } ]
        [ 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 ( join_column [, ...] ) [ AS join_using_alias ] }
        é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 )
            [ SEARCH { BREADTH | DEPTH } FIRST BY nom_colonne [, ...] SET search_seq_col_name ]
            [ CYCLE nom_colonne [, ...] SET cycle_mark_col_name [ TO cycle_mark_value DEFAULT cycle_mark_default ] USING cycle_path_col_name ]

    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 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 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 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 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. Clause DISTINCT 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 Clause UNION, Clause INTERSECT et 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 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 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 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 clause optionnelle `SEARCH` calcule une colonne de séquence de recherche qui peut être utilisé pour trier les résultats d'une requête récursive soit en breadth-first ou des depth-first. La liste de noms de colonnes fournie indique la clé de ligne qui est utilisée pour garder trace des lignes visitées. Une colonne nommée `search_seq_col_name` sera ajoutée à la liste des colonnes résultats de la requête `WITH`. Cette colonne peut être triée dans la requête externe pour réaliser le tri demandé. Voir Section 7.8.2.1 pour des exemples.

La clause optionnelle `CYCLE` est utilisé pour détecter les cycles dans les requêtes récursives. La liste des noms de colonnes fournie indiqué la clé de ligne qui est à utiliser pour garder trace des lignes visitées. Une colonne nommée `cycle_mark_col_name` sera ajoutée à la liste de colonnes en résultat de la requête `WITH`. Cette colonne est initialisée à `cycle_mark_value` quand un cycle est détecté, et sinon à `cycle_mark_default`. De plus, le traitement de l'union récursif s'arrêtera quand un cycle aura été détecté. `cycle_mark_value` et `cycle_mark_default` doivent être des constantes et elles sont convertibles automatiquement vers un type de données commun. Le type de données doit avoir un opérateur d'inégalité. (Le standard SQL requiert qu'elles doivent être de type booléen ou chaîne de caractères, mais PostgreSQL ne l'oblige pas.) Par défaut, `TRUE` et `FALSE` (de type `boolean`) sont utilisés. De plus, une colonne nommée `cycle_path_col_name` sera ajoutée à la liste de colonnes en résultat de la requête `WITH`. Cette colonne est utilisée en interne pour traquer les lignes visitées. Voir Section 7.8.2.2 pour des exemples.

Les clauses `SEARCH` et `CYCLE` sont seulement valides pour les requêtes `WITH` récursives. `with_query` doit être une `UNION`(ou `UNION ALL`) de deux commandes `SELECT` (ou équivalent) commands (pas de `UNION`imbriqués). Si les deux clauses sont utilisées, la colonne ajoutée par la clause `SEARCH` apparaît avant les colonnes ajoutées par la clause `CYCLE`.

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, `BERNOULLI`et `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'échantillonnage 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`. Si le type du résultat de la fonction est composite (en incluant le cas d'une fonction avec plusieurs paramètres `OUT`), chaque attribut devient une colonne séparée dans la table implicite.

  Quand la clause optionnelle `WITH ORDINALITY` est ajoutée à l'appel de fonction, une colonne supplémentaire de type `bigint` sera ajouté aux colonnes du résultat de la fonction. Cette colonne numérote les lignes de l'ensemble de résultats de la fonction, en commençant à 1. Par défaut, cette colonne est nommée `ordinality`.

  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 numérotée automatiquement.

  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 renvoie 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` [, ...]) [ AS `jointure_utilisant_alias` ]`

  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.

  Si un nom `jointure_utilisant_alias` est indiqué, il fournit un alias de table pour les colonnes de la jointure. Seules les colonnes de la jointure listées dans la clause `USING` sont adressables par ce nom. Contrairement à l'habituel `alias`, cela ne cache pas les noms des tables jointes du reste de la requête. De plus, contrairement à un `alias` standard, vous ne pouvez pas écrire une liste d'alias de colonnes -- les noms en sortie des colonnes de jointure sont identiques à comment elles apparaissent en utilisant la liste `USING`.

`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 [ ALL | DISTINCT ] 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`. La clause optionnelle `DISTINCT` supprime les ensembles dupliqués avant le traitement ; elle ne transforme pas le `UNION ALL` en un `UNION DISTINCT`. 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 d'une 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 `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 `SELECT` ou la 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 clause`WHERE` 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é.

### Clause `DISTINCT`

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 24.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 | WITH TIES }

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. L'option `WITH TIES` est utilisée pour renvoyer toute ligne supplémentaire qui se lie pour la dernière place dans le jeu de résultats selon la clause `ORDER BY` ; `ORDER BY` est requis dans ce cas, et `SKIP LOCKED` n'est pas autorisé. `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`.

### 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 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.