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_d_affichage
] [, ...] ] [ FROMéléments_from
[, ...] ] [ WHEREcondition
] [ GROUP BYelement_regroupement
[, ...] ] [ HAVINGcondition
] [ WINDOWnom_window
AS (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 ] [ FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OFnom_table
[, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ] avecéléments_from
qui 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_from
[ NATURAL ]type_jointure
éléments_from
[ ONcondition_jointure
| USING (colonne_jointure
[, ...] ) ] etelement_regroupement
peut valoir : ( )expression
(expression
[, ...] ) ROLLUP ( {expression
| (expression
[, ...] ) } [, ...] ) CUBE ( {expression
| (expression
[, ...] ) } [, ...] ) GROUPING SETS (element_regroupement
[, ...] ) etrequête_with
est :nom_requête_with
[ (nom_colonne
[, ...] ) ] AS (select
|valeurs
|insert
|update
|delete
) 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
(voir la section intitulée « 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 la section intitulée « 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
la section intitulée « 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 la section intitulée « Clause GROUP BY
» et la section intitulée « Clause HAVING
» ci-dessous.)
Les lignes retournées sont traitées en utilisant les expressions de sortie
de SELECT
pour chaque ligne ou groupe de ligne sélectionné. (Voir la section intitulée « Liste SELECT
» ci-dessous.)
SELECT DISTINCT
élimine du résultat les lignes en double.
SELECT DISTINCT ON
élimine les lignes qui correspondent sur toute l'expression spécifiée.
SELECT ALL
(l'option par défaut) retourne toutes les lignes, y compris les doublons.
(cf. DISTINCT
Clause ci-dessous.)
En utilisant les opérateurs UNION
,
INTERSECT
et EXCEPT
, l'affichage de
plusieurs instructions SELECT
peut être combiné pour
former un ensemble unique de résultats. L'opérateur UNION
renvoie toutes les lignes qui appartiennent, au moins, à l'un des ensembles de
résultats. L'opérateur INTERSECT
renvoie toutes les
lignes qui sont dans tous les ensembles de résultats.
L'opérateur EXCEPT
renvoie les lignes qui sont
présentes dans le premier ensemble de résultats mais pas dans le
deuxième. Dans les trois cas, les lignes dupliquées sont éliminées sauf
si ALL
est spécifié. Le mot-clé supplémentaire
DISTINCT
peut être ajouté pour signifier explicitement que
les lignes en doublon sont éliminées. Notez bien que DISTINCT
est
là le comportement par défaut, bien que ALL
soit
le défaut pour la commande SELECT
. (Voir la section intitulée « Clause UNION
», la section intitulée « Clause INTERSECT
» et la section intitulée « Clause EXCEPT
» ci-dessous.)
Si la clause ORDER BY
est spécifiée, les lignes
renvoyées sont triées dans l'ordre spécifié. Si ORDER
BY
n'est pas indiqué, les lignes sont retournées dans l'ordre
qui permet la réponse la plus rapide du système. (Voir la section intitulée « Clause ORDER BY
» ci-dessous.)
Si les clauses LIMIT
(ou FETCH FIRST
)
ou OFFSET
sont
spécifiées, l'instruction SELECT
ne renvoie qu'un
sous-ensemble de lignes de résultats. (Voir la section intitulée « Clause LIMIT
» ci-dessous.)
Si la clause FOR UPDATE
, FOR NO KEY UPDATE
,
FOR SHARE
ou FOR KEY SHARE
est spécifiée,
l'instruction SELECT
verrouille les lignes sélectionnées contre les mises à jour concurrentes.
(Voir la section intitulée « Clause de verrouillage » ci-dessous.)
Le droit SELECT
sur chaque colonne utilisée dans une
commande SELECT
est nécessaire pour lire
ses valeurs. L'utilisation de FOR NO KEY UPDATE
,
FOR UPDATE
, FOR SHARE
ou
FOR KEY SHARE
requiert en plus le droit
UPDATE
(pour au moins une colonne de chaque table
sélectionnée).
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
.
Une propriété clé des requêtes WITH
est qu'elles ne sont
évaluées qu'une seule fois par exécution de la requête principale,
même si la requê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.
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).
Tout se passe comme si la requête principale et les requêtes WITH
étaient toutes
exécutées en même temps. Ceci a pour conséquence que les effets d'un ordre de modification dans une clause
WITH
ne peuvent pas être vues des autres parties de la requête, sauf en lisant la sortie
de RETURNING
. Si deux de ces ordres de modifications tentent de modifier la même ligne,
les résultats sont imprévisibles.
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, 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'échantillonage supplémentaires pourraient ne pas
accepter la clausse REPEATABLE
, et toujours
produire de nouveau échantillon à chaque utilisation.
select
Un sous-SELECT
peut apparaître dans la clause
FROM
. Il agit comme si sa sortie était
transformée en table temporaire pour la durée de cette seule commande
SELECT
. Le sous-SELECT
doit être entouré de parenthèses et un alias
doit lui être fourni.
Une commande VALUES
peut aussi être utilisée ici.
requête_with
Une requête WITH
est référencée par l'écriture de
son nom, exactement comme si le nom de la requête était un nom de table
(en fait, la requête WITH
cache toutes les tables
qui auraient le même nom dans la requête principale. Si nécessaire, vous
pouvez accéder à une table réelle du même nom en précisant le schéma
du nom de la table).
Un alias peut être indiqué de la même façon que pour une table.
nom_fonction
Des appels de fonctions peuvent apparaître dans la clause
FROM
. (Cela est particulièrement utile pour les
fonctions renvoyant des ensembles de résultats, mais n'importe quelle fonction peut
être utilisée.) Un appel de fonction agit comme si la sortie de la
fonction était créée comme une table temporaire pour la durée de
cette seule commande SELECT
. Quand la clause
optionnelle WITH ORDINALITY
est ajoutée à l'appel
de la fonction, une nouvelle colonne est ajoutée après toutes les
colonnes en sortie de la fonction numérotant ainsi chaque ligne.
Un alias peut être fourni de la même façon pour une table. Si un alias
de table est donné, une liste d'alias de colonnes peut aussi être écrite
pour fournir des noms de substitution pour un ou plusieurs attributs du
type composite en retour de la fonction, ceci incluant la colonne ajoutée
par ORDINALITY
.
Plusieurs appels de fonction peuvent être combinés en un seul élément
dans la clause FROM
en les entourant de ROWS
FROM( ... )
. La sortie d'un tel élément est la concaténation
de la première ligne de chaque fonction, puis la deuxième ligne de
chaque fonction, etc. Si certaines fonctions produisent moins de lignes
que d'autres, des NULL sont ajoutées pour les données manquantes, ce
qui permet d'avoir comme nombre de lignes celui de la fonction qui en
renvoit le plus.
Si la fonction a été définie comme renvoyant le type de données
record
, un alias ou le mot clé AS
doivent
être présents, suivi par une liste de définition de colonnes de la
forme (
. 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_jointure
Un des éléments
[ INNER ] JOIN
LEFT [ OUTER ] JOIN
RIGHT [ OUTER ] JOIN
FULL [ OUTER ] JOIN
CROSS JOIN
Pour les types de jointures INNER
et OUTER
, une
condition de jointure doit être spécifiée, à choisir parmi
NATURAL
, ON
ou
condition_jointure
USING (
.
Voir ci-dessous pour la signification. Pour colonne_jointure
[, ...])CROSS
JOIN
, aucune de ces clauses ne doit apparaître.
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
.
CROSS JOIN
et INNER JOIN
produisent un
simple produit cartésien. Le résultat est identique à celui obtenu
lorsque les deux tables sont listés au premier niveau du FROM
, mais
restreint par la condition de jointure (si elle existe). CROSS
JOIN
est équivalent à INNER JOIN ON (TRUE)
, c'est-à-dire
qu'aucune ligne n'est supprimée par qualification. Ces types de
jointure sont essentiellement une aide à la notation car ils ne font rien de
plus qu'un simple FROM
et WHERE
.
LEFT OUTER JOIN
renvoie toutes les lignes du produit
cartésien qualifié (c'est-à-dire toutes les lignes combinées qui
satisfont la condition de jointure), plus une copie de chaque ligne
de la table de gauche pour laquelle il n'y a pas de ligne à droite
qui satisfasse la condition de jointure. La ligne de gauche est
étendue à la largeur complète de la table jointe par insertion de
valeurs NULL pour les colonnes de droite. Seule la
condition de la clause JOIN
est utilisée pour décider des
lignes qui correspondent. Les conditions externes sont appliquées après
coup.
À l'inverse, RIGHT OUTER JOIN
renvoie toutes les lignes
jointes plus une ligne pour chaque ligne de droite sans correspondance
(complétée par des NULL pour le côté gauche). C'est une simple aide à
la notation car il est aisément convertible en LEFT
en
inversant les tables gauche et droite.
FULL OUTER JOIN
renvoie toutes les lignes jointes, plus
chaque ligne gauche sans correspondance (étendue par des NULL à droite),
plus chaque ligne droite sans correspondance (étendue par des NULL à
gauche).
ON condition_jointure
condition_jointure
est une expression qui retourne une valeur de type boolean
(comme une clause WHERE
) qui spécifie les
lignes d'une jointure devant correspondre.
USING (colonne_jointure
[,
...])
Une clause de la forme USING ( a, b, ... )
est un
raccourci pour ON table_gauche.a = table_droite.a AND table_gauche.b
= table_droite.b ...
. De plus, USING
implique
l'affichage d'une seule paire des colonnes correspondantes dans la sortie
de la jointure.
NATURAL
NATURAL
est un raccourci pour une liste
USING
qui mentionne toutes les colonnes de même nom
dans les deux tables. USING
qui mentionne toutes
les colonnes de même nom dans les deux tables. S'il n'y a pas de noms
de colonnes communs, NATURAL
est équivalent à
ON TRUE
.
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
est valide
syntaxiquement, il n'est pas permis à X
RIGHT JOIN
LATERAL Y
Y
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 element_regroupement
[, ...]
GROUP BY
condensera en une seule ligne toutes les
lignes sélectionnées partageant les mêmes valeurs pour les expressions
regroupées. Une expression
utilisée à l'intérieur d'un element_regroupement
peut être un nom de
colonne en entrée, ou le nom ou le numéro d'une colonne en sortie (élément
de la liste SELECT
), ou une expression arbitraire
formée à partir des valeurs ou colonnes en entrée. En cas d'ambiguité, un
nom GROUP BY
sera interprété comme un nom de colonne en
entrée plutôt qu'en tant que nom de colonne en sortie.
Si une clause parmi GROUPING SETS
,
ROLLUP
ou CUBE
est présente comme
élément de regroupement, alors la clause GROUP BY
dans
sa globalité définit un certain nombre d'ensembles de
regroupement
indépendants. L'effet de ceci est l'équivalent
de la construction d'un UNION ALL
des sous-requêtes
pour chaque ensemble de regroupement individuel avec leur propre clause
GROUP BY
. Pour plus de détails sur la gestion des
ensembles de regroupement, voir Section 7.2.4.
Les fonctions d'agrégat, si utilisées, sont calculées pour toutes les lignes
composant un groupe, produisant une valeur séparée pour chaque groupe. (S'il
y a des fonctions d'agrégat mais pas de clause GROUP BY
,
la requête est traitée comme ayant un seul groupe contenant toutes les lignes
sélectionnées.)
L'ensemble de lignes envoyées à la fonction d'agrégat peut être en plus filtré
en ajoutant une clause FILTER
lors de l'appel à la fonction
d'agrégat ; voir Section 4.2.7 pour plus
d'informations. Quand une clause FILTER
est présente,
seules les lignes correspondant au filtre sont incluses en entrée de cette
fonction d'agrégat.
Quand GROUP BY
est présent ou que des fonctions d'agrégat
sont présentes, les expressions du SELECT
ne peuvent faire
référence qu'à des colonnes groupées, sauf à l'intérieur de fonctions
d'agrégat, ou bien si la colonne non groupée dépend fonctionnellement des colonnes groupées.
En effet, s'il en était autrement, il y aurait plus d'une valeur possible pour la colonne non groupée.
Une dépendance fonctionnelle existe si les colonnes groupées (ou un sous-ensemble de ces dernières) sont la clé primaire de la
table contenant les colonnes non groupées.
Rappelez-vous que toutes les fonctions d'agrégat sont évaluées avant
l'évaluation des expressions « scalaires » dans la clause
HAVING
ou la liste SELECT
. Ceci
signifie que, par exemple, une expression CASE
ne
peut pas être utilisée pour ignorer l'évaluation de la fonction
d'agrégat ; voir Section 4.2.14.
Actuellement, FOR NO KEY UPDATE
, FOR
UPDATE
, FOR SHARE
et FOR KEY
SHARE
ne peuvent pas être spécifiées avec GROUP
BY
.
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_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 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 de la section intitulée « Clause GROUP BY
», sauf qu'ils sont toujours des expressions
simples et jamais le nom ou le numéro d'une colonne en sortie.
Une autre différence est que ces expressions peuvent contenir des appels
à des fonctions d' agrégat, ce qui n'est pas autorisé dans une clause
GROUP BY
classique. Ceci est autorisé ici parce que
le windowing se produit après le regroupement et l' agrégation.
De façon similaire, les éléments de la liste ORDER BY
sont interprétés à peu près de la même façon que les éléments d'un la section intitulée « Clause ORDER BY
», sauf que les expressions
sont toujours prises comme de simples expressions et jamais comme le nom ou
le numéro d'une colonne en sortie.
La clause clause_frame
optionnelle définit la frame window pour les
fonctions window qui dépendent de la frame (ce n'est pas le cas de toutes).
La frame window est un ensemble de lignes liées à chaque ligne de la requête (appelée la ligne courante).
La clause_frame
peut être une des clauses suivantes :
{ RANGE | ROWS }début_portée
{ RANGE | ROWS } BETWEENdébut_portée
ANDfin_portée
où début_frame
et fin_frame
peuvent valoir
UNBOUNDED PRECEDINGvaleur
PRECEDING CURRENT ROWvaleur
FOLLOWING UNBOUNDED FOLLOWING
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 le choix
début_frame
-- par exemple
RANGE BETWEEN CURRENT ROW AND
n'est pas permis.
valeur
PRECEDING
L'option par défaut pour la clause frame est RANGE UNBOUNDED PRECEDING
,
ce qui revient au même que RANGE BETWEEN UNBOUNDED PRECEDING AND
CURRENT ROW
; il positionne la frame pour qu'il couvre toutes les lignes à partir du début de la partition
jusqu'à la dernière ligne à égalité avec la ligne courante (une ligne que
la clause ORDER BY
considère équivalente à la ligne
actuelle ou à toutes les lignes s'il n'y a pas de clause ORDER
BY
).
Généralement, UNBOUNDED PRECEDING
signifie que la frame commence
à la première ligne de la partition, et de même
UNBOUNDED FOLLOWING
signifie que la frame se termine avec la dernière ligne
de la partition (quel que soit le mode, RANGE
ou bien ROWS
). Dans le mode ROWS
, CURRENT ROW
signifie que la frame commence ou se termine sur la ligne courante ; mais
dans le mode RANGE
cela signifie que la frame débute ou se termine
sur la première ou la dernière des lignes à égalité avec la ligne courante
dans l'ordre de la clause ORDER BY
.
Les valeur
PRECEDING
et
valeur
FOLLOWING
sont actuellement seulement
permis en mode ROWS
. Ils indiquent que la frame débute ou se termine
autant de lignes avant ou après la ligne courante.
valeur
doit être une expression entière,
ne contenant aucune variable, fonction d' agrégat ni fonction window.
La valeur ne doit être ni null ni négative ; mais elle peut être de zéro, ce qui sélectionne
la ligne courante elle-même.
Attention, les options ROWS
peuvent produire des résultats imprévisibles
si l'ordre défini par l' ORDER BY
n'ordonne pas les lignes de
manière unique. Les options RANGE
sont conçues pour s'assurer que
les lignes qui sont à égalité suivant l'ordre de l' ORDER BY
sont traitées
de la même manière ; toutes les lignes à égalité
seront ensemble dans la frame ou ensemble hors de la frame.
L'utilité d'une clause WINDOW
est de spécifier le
comportement des fonctions window apparaissant dans
la clause la section intitulée « Liste SELECT
»
ou la clause la section intitulée « Clause ORDER BY
» de
la requête. Ces fonctions peuvent référencer les entrées de clauses
WINDOW
par nom dans leurs clauses OVER
.
Toutefois, il n'est pas obligatoire qu'une entrée de clause
WINDOW
soit référencée quelque part ; si elle n'est
pas utilisée dans la requête, elle est simplement ignorée. Il est possible
d'utiliser des fonctions window sans aucune clause WINDOW
puisqu'une fonction window peut spécifier sa propre définition de window
directement dans sa clause OVER
. Toutefois, la clause
WINDOW
économise de la saisie quand la même définition
window est utilisée pour plus d'une fonction window.
Actuellement, FOR NO KEY UPDATE
, FOR
UPDATE
, FOR SHARE
et FOR KEY
SHARE
ne peuvent pas être spécifiées avec GROUP
BY
.
Les fonctions window sont décrites en détail dans Section 3.5, Section 4.2.8 et Section 7.2.5.
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,
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
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
Clause
Si SELECT DISTINCT
est spécifié, toutes les lignes en double sont
supprimées de l'ensemble de résultats (une ligne est conservée pour chaque groupe
de doublons). SELECT ALL
spécifie le contraire : toutes les lignes sont
conservées. C'est l'option par défaut.
SELECT DISTINCT ON (
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_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
.
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
.
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
.
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 } OFFSETdé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
Avec cette syntaxe, la valeur de start
et de count
doit être une constante, un
paramètre ou un nom de variable d'après la norme ; PostgreSQL étend
ça à toute expression mais il sera généralement nécessaire de l'entourer
de parenthèses pour éviter toute ambiguïté.
Si compte
est omis dans une clause
FETCH
, il vaut 1 par défaut.
ROW
et ROWS
ainsi que FIRST
et NEXT
sont des mots qui n'influencent pas les
effets de ces clauses.
D'après le standard, la clause OFFSET
doit venir
avant la clause FETCH
si les deux sont
présentes ; PostgreSQL est plus laxiste et
autorise un ordre différent.
Avec LIMIT
, utiliser la clause
ORDER BY
permet de contraindre l'ordre des lignes de
résultat. Dans le cas contraire, le sous-ensemble obtenu n'est pas prévisible --
rien ne permet de savoir à quel ordre correspondent les lignes retournées.
Celui-ci ne sera pas connu tant qu'ORDER BY
n'aura pas été précisé.
Lors de la génération d'un plan de requête, le planificateur tient compte
de LIMIT
. Le risque est donc grand d'obtenir des plans
qui diffèrent (ordres des lignes différents) suivant les valeurs
utilisées pour LIMIT
et OFFSET
. Ainsi, sélectionner
des sous-ensembles différents d'un résultat à partir de valeurs différentes
de LIMIT
/OFFSET
aboutit à des résultats
incohérents à moins d'avoir figé l'ordre des lignes à l'aide
de la clause ORDER BY
. Ce n'est pas un bogue, mais une conséquence
du fait que SQL n'assure pas l'ordre de présentation des résultats sans
utilisation d'une clause ORDER BY
.
Il est même possible pour des exécutions répétées de la même requête
LIMIT
de renvoyer différents sous-ensembles des lignes
d'une table s'il n'y a pas de clause ORDER BY
pour forcer
la sélection d'un sous-ensemble déterministe. Encore une fois, ce n'est pas
un bogue ; le déterminisme des résultats n'est tout simplement pas
garanti dans un tel cas.
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
[ OFnom_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.
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.
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.
Joindre la table films
avec la table
distributeurs
:
SELECT f.titre, f.did, d.nom, f.date_prod, f.genre FROM distributeurs d, films f WHERE f.did = d.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
.
S'il n'y a pas de clause FROM
, la requête ne
peut pas référencer les tables de la base de données. La
requête suivante est, ainsi, invalide :
SELECT distributors.* WHERE distributors.name = 'Westward';
Les versions antérieures à PostgreSQL 8.1
acceptaient les requêtes de cette forme en ajoutant une entrée implicite à
la clause FROM
pour chaque table référencée.
Ce n'est plus autorisé.
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.
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
(...) alias
FROM LATERAL (SELECT
.
Notez que fonc
(...)) alias
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.
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.
WINDOW
Le standard SQL fournit des options additionnelles pour la
clause_frame
des window.
PostgreSQL ne supporte à ce jour que les options
mentionnées précédemment.
LIMIT
et OFFSET
Les clauses LIMIT
et OFFSET
sont une syntaxe spécifique à PostgreSQL, aussi
utilisée dans MySQL. La norme SQL:2008 a
introduit les clauses OFFSET ... FETCH {FIRST|NEXT}...
pour la même fonctionnalité, comme montré plus haut dans
la section intitulée « Clause LIMIT
». Cette syntaxe
est aussi utilisée par IBM DB2.
(Les applications écrites pour Oracle contournent
fréquemment le problème par l'utilisation de la colonne auto-générée
rownum
pour obtenir les effets de ces clauses, qui n'est
pas disponible sous PostgreSQL,)
FOR NO KEY UPDATE
, FOR UPDATE
, FOR SHARE
, FOR KEY SHARE
Bien que FOR UPDATE
soit présent dans le standard SQL, le standard
ne l'autorise que comme une option de DECLARE CURSOR
.
PostgreSQL l'autorise dans toute requête SELECT
et dans toute sous-requête SELECT
, mais c'est une extension.
Les variantes FOR NO KEY UPDATE
, FOR
SHARE
et FOR KEY SHARE
, ainsi que
NOWAIT
et SKIP LOCKED
,
n'apparaissent pas dans le standard.
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.
La clause DISTINCT ON
est une extension du standard
SQL.
ROWS FROM( ... )
est une extension du standard
SQL.