

SELECT, TABLE, WITH — récupère des lignes d'une table ou d'une vue
[ WITH [ RECURSIVE ]requête_with[, ...] ] SELECT [ ALL | DISTINCT [ ON (expression[, ...] ) ] ] [ { * |expression[ [ AS ]nom_sortie] } [, ...] ] [ FROMéléments_from[, ...] ] [ WHEREcondition] [ GROUP BY [ ALL | DISTINCT ]element_regroupement[, ...] ] [ HAVINGcondition] [ WINDOWnom_windowAS (définition_window) [, ...] ] [ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ]select] [ ORDER BYexpression[ ASC | DESC | USINGopérateur] [ NULLS { FIRST | LAST } ] [, ...] ] [ LIMIT {nombre| ALL } ] [ OFFSETdébut] [ ROW | ROWS ] ] [ FETCH { FIRST | NEXT } [total] { ROW | ROWS } { ONLY | WITH TIES } ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OFreference_from[, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ] avecéléments_fromqui peut être : [ ONLY ]nom_table[ * ] [ [ AS ]alias[ (alias_colonne[, ...] ) ] ] [ TABLESAMPLEmethode_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éments_fromtype_jointureélément_from{ ONtype_jointure| USING (colonne_jointure[, ...] ) [ ASjointure_utilisant_alias] }élément_fromNATURALtype_jointureélément_fromélément_fromCROSS JOINélément_frometelement_regroupementpeut valoir : ( )expression(expression[, ...] ) ROLLUP ( {expression| (expression[, ...] ) } [, ...] ) CUBE ( {expression| (expression[, ...] ) } [, ...] ) GROUPING SETS (element_regroupement[, ...] ) etrequête_withest :nom_requête_with[ (nom_colonne[, ...] ) ] AS [ [ NOT ] MATERIALIZED ] (select|values|insert|update|delete|merge) [ SEARCH { BREADTH | DEPTH } FIRST BYnom_colonne[, ...] SETsearch_seq_col_name] [ CYCLEnom_colonne[, ...] SETcycle_mark_col_name[ TOcycle_mark_valueDEFAULTcycle_mark_default] USINGcycle_path_col_name] TABLE [ ONLY ]nom_table[ * ]
   SELECT récupère des lignes de zéro ou plusieurs
   tables. Le traitement général de SELECT est le
   suivant :
   
      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).
     
      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.)
     
      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.)
     
      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.
     
      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.)
     
      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.)
     
      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.)
     
      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.)
     
      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.)
     
      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).
  
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,
    DELETE ou MERGE.
    Lorsque vous écrivez un ordre de modification de données
    (INSERT, UPDATE,
    DELETE ou MERGE) 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écursifUNION [ 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
    UNIONimbriqué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.
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'é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
        peut lui être fourni de la même façon que pour une table.
        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 ( . 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.
       nom_colonne type_donnée [, ...
         ])
        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_jointureUn 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  ou
        condition_jointureUSING (,
        ou colonne_jointure [, ...])NATURAL.
        Voir ci-dessous pour la signification.
       
        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 de JOIN sont une facilité
        d'écriture car elles ne font rien que vous ne pourriez faire avec des
        clauses FROM et WHERE basiques.
       
        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), autrement dit, aucune ligne n'est supprimé par la
        qualification. Ils réalisent un produit cartésien, vous obtenez le même
        résultat en listant les deux tables au plus haut niveau de
        FROM mais restreinte par 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 YY de
        référencer X.
       
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.
   
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.
   
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.
   
WINDOW
    La clause optionnelle WINDOW a la forme générale
    
WINDOWnom_windowAS (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 BYexpression[, ...] ] [ ORDER BYexpression[ ASC | DESC | USINGoperateur] [ 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 PRECEDINGdécalagePRECEDING CURRENT ROWdécalageFOLLOWING 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  n'est pas permis.
   décalage
     PRECEDING
    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.
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.*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.
   
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
    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 ( 
    conserve seulement la première ligne de chaque ensemble de lignes pour lesquelles le résultat
    de l'expression est identique. Les expressions expression [, ...] )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.
   
UNION
    La clause UNION a la forme générale :
    
instruction_selectUNION [ 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.
   
INTERSECT
    La clause INTERSECT a la forme générale :
    
instruction_selectINTERSECT [ 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.
   
EXCEPT
    La clause EXCEPT a la forme générale :
    
instruction_selectEXCEPT [ 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.
   
ORDER BY
    La clause optionnelle ORDER BY a la forme
    générale :
    
ORDER BYexpression[ ASC | DESC | USINGopé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.
   
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.
OFFSETdé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.
   
    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 :
FORforce_verrou[ OFreference_from[, ...] ] [ NOWAIT | SKIP LOCKED ]
    où force_verrou fait partie de :
    
UPDATE
NO KEY UPDATE
SHARE
KEY SHARE
    
    reference_from doit être
    un alias de table ou un
    nom_table non caché référencé
    dans la clause FROM. Pour plus d'informations sur
    chaque mode de verrou de niveau ligne, référez-vous à
    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.
   
     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.
    
TABLELa 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.
   
   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;
   L'instruction SELECT est évidemment compatible avec le
   standard SQL. Mais il y a des extensions et quelques fonctionnalités
   manquantes.
  
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.
   
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é.
   
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.
   
SELECT dans FROM
    D'après le standard SQL, un sous-SELECT dans la liste
    FROM doit avoir un alias. Avec
    PostgreSQL, cet alias peut être omis.
   
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.)
   
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.
   
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 
    est à peu près équivalente à
    fonc(...) aliasFROM LATERAL (SELECT .
    Notez que fonc(...)) aliasLATERAL 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.
   
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.
   
    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.
   
WITH
    PostgreSQL permet que les clauses
    INSERT, UPDATE,
    DELETE et MERGE soient utilisées
    comme requêtes WITH. Ceci n'est pas présent dans le
    standard SQL.
   
    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.