SELECT
SELECT — récupère des lignes d'une table ou d'une vue
Synopsis
SELECT [ ALL | DISTINCT [ ON ( expression [, ...] ) ] ]
* | expression [ AS nom_d_affichage ] [, ...]
[ FROM éléments_from [, ...] ]
[ WHERE condition ]
[ GROUP BY expression [, ...] ]
[ HAVING condition [, ...] ]
[ { UNION | INTERSECT | EXCEPT } [ ALL ] select ]
[ ORDER BY expression [ ASC | DESC | USING opérateur ] [, ...] ]
[ LIMIT { nombre | ALL } ]
[ OFFSET début ]
[ FOR { UPDATE | SHARE } [ OF nom_table [, ...] ] [ NOWAIT ] [...] ]
avec éléments_from qui peut être :
[ ONLY ] nom_table [ * ] [ [ AS ] alias [ ( alias_colonne [, ...] ) ] ]
( select ) [ AS ] alias [ ( alias_colonne [, ...] ) ]
nom_fonction ( [ argument [, ...] ] ) [ AS ] alias [ ( alias_colonne [, ...] | définition_colonne [, ...] ) ]
nom_fonction ( [ argument [, ...] ] ) AS ( définition_colonne [, ...] )
éléments_from [ NATURAL ] type_jointure éléments_from [ ON condition_jointure | USING ( colonne_jointure [, ...] ) ]
Description
SELECT
récupère des
lignes de zéro ou plusieurs tables. Le traitement général de
SELECT
est le suivant
:
-
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,
l'affichage est divisé en groupes de lignes qui correspondent
à une ou plusieurs valeurs. 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.)
-
Les lignes retournées sont traitées en utilisant les
expressions de sortie de
SELECT
pour chaque ligne
sélectionnée. (Voir Liste
SELECT
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é. (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.)
-
DISTINCT élimine les lignes
dupliquées du résultat. DISTINCT ON
élimine les lignes qui correspondent à toutes les expressions
données. ALL (la valeur par défaut)
renvoie toutes les lignes candidates, y compris les lignes
dupliquées. (Voir Clause
DISTINCT
ci-dessous.)
-
Si les clauses LIMIT 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 ou
FOR SHARE est spécifiée,
l'instruction
SELECT
verrouille les
lignes sélectionnées contre les mises à jour concurrentes.
(Voir Clause FOR
UPDATE/FOR SHARE
ci-dessous.)
Le droit SELECT sur une table est
nécessaire pour lire ses valeurs. L'utilisation de FOR UPDATE ou de FOR SHARE
requiert en plus le droit UPDATE.
Paramètres
Clause FROM
La clause FROM spécifie une ou plusieurs
tables source pour le
SELECT
. Si plusieurs sources
sont spécifiées, le résultat est un produit cartésien (jointure
croisée) de toutes les sources. Mais habituellement, des
conditions de qualification 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 existante ou d'une vue. Si ONLY est spécifié, seule cette table est
parcourue. Dans le cas contraire, la table et toutes ses
descendantes (s'il y en a) sont parcourues. * peut être ajouté au nom de la table pour
indiquer que les tables descendantes doivent être
parcourues mais, dans la version actuelle, c'est le
comportement par défaut. Dans les versions précédant la
7.1, ONLY était le comportement
par défaut. Ce dernier peut être modifié à l'aide de
l'option de configuration sql_inheritance.
-
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 foo AS, le reste du
SELECT
doit
faire référence à cet élément de FROM par f et non
pas par foo. 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.
-
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.
-
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
était transformée en table temporaire pour la durée de
cette seule commande
SELECT
. Un alias peut
aussi être utilisé. Si un alias est donné, une liste
d'alias de colonnes peut être ajoutée pour fournir des noms
de substitution pour un ou plusieurs attributs du type
composé de retour de la fonction. Si la fonction a été
définie comme renvoyant le type de données record, alors un alias ou un mot clé
AS doit être présent, suivi par
une liste de définitions de colonnes de la forme (
nom_colonne
type_données
[, ... ] ). La liste de définitions
de colonnes doit correspondre au nombre réel et aux types
réels des colonnes renvoyées par la fonction.
-
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
condition_jointure
ou
USING (
colonne_jointure
[, ...]).
Voir ci-dessous pour la signification. Pour CROSS JOIN, aucune de ces clauses ne doit
apparaître.
Une clause JOIN combine deux
éléments 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 éléments 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 entrées 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.
Clause WHERE
La clause WHERE optionnelle a la forme
générale
WHERE condition
où
condition
est une
expression dont le résultat est de type boolean. Toute ligne qui ne satisfait pas cette
condition est éliminée de la sortie. Une ligne satisfait la
condition si elle retourne vrai quand les valeurs réelles de la
ligne sont substituées à toute référence de variable.
Clause GROUP BY
La clause GROUP BY optionnelle a la
forme générale
GROUP BY expression [, ...]
GROUP BY condense en une seule ligne
toutes les lignes sélectionnées qui partagent les mêmes valeurs
pour les expressions regroupées.
expression
peut être le nom d'une
colonne en entrée, le nom ou le numéro d'une colonne en sortie
(élément de la liste
SELECT
), ou une expression
quelconque formée de valeurs de colonnes en entrée. En cas
d'ambiguïté, un nom de GROUP BY est
interprété comme un nom de colonne en entrée, non en sortie.
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 (alors que sans GROUP
BY, un agrégat produit une valeur unique calculée pour
toutes les lignes sélectionnées). Quand GROUP
BY est présent, les expressions du
SELECT
ne peuvent faire
référence qu'à des colonnes groupées, sauf à l'intérieur de
fonctions d'agrégat, la valeur de retour d'une colonne
non-groupée n'étant pas unique.
Clause HAVING
La clause optionnelle HAVING a la forme
générale
HAVING condition
où
condition
est identique
à celle spécifiée pour la clause WHERE.
HAVING élimine les lignes groupées qui
ne satisfont pas à la condition. HAVING
est différent de WHERE : WHERE filtre les lignes individuelles avant
l'application de GROUP BY alors que
HAVING filtre les lignes groupées créées
par GROUP BY. Chaque colonne référencée
dans
condition
doit faire
référence sans ambiguïté à une colonne groupée, sauf si la
référence apparaît dans une fonction d'agrégat.
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.
Liste
SELECT
La liste
SELECT
(entre les mots clés SELECT et
FROM) spécifie les expressions qui
forment les lignes en sortie de l'instruction
SELECT
. Il se peut que les
expressions fassent (en général elles le font) référence aux
colonnes traitées dans la clause FROM.
L'utilisation de la clause AS
nom_sortie
permet de modifier le
nom d'une colonne en sortie. Ce nom est principalement utilisé
pour l'affichage. Il peut aussi l'être pour référencer la valeur
de la colonne dans les clauses ORDER BY
et GROUP BY. Il ne peut en revanche pas
être utilisé dans les clauses WHERE ou
HAVING ; il faudra dans ce cas écrire
les expressions.
* peut être utilisé, à la place d'une
expression, dans la liste de sortie comme raccourci pour toutes
les colonnes des lignes sélectionnées. De plus,
nom_table
.*
peut être écrit comme raccourci pour toutes les colonnes de cette
table.
Clause UNION
La clause UNION a la forme générale :
instruction_select UNION [ ALL ] 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é.
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 UPDATE et FOR SHARE ne peuvent pas être spécifiés pour un
résultat d'UNION ou pour toute entrée
d'un UNION.
Clause INTERSECT
La clause INTERSECT a la forme générale
:
instruction_select INTERSECT [ ALL ] instruction_select
instruction_select
est une
instruction
SELECT
sans clause ORDER BY, LIMIT, FOR UPDATE ou
FOR 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.
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 UPDATE et FOR SHARE ne peuvent pas être spécifiés pour un
résultat d'INTERSECT ou pour une entrée
d'INTERSECT.
Clause EXCEPT
La clause EXCEPT a la forme générale :
instruction_select EXCEPT [ ALL ] instruction_select
instruction_select
est une
instruction
SELECT
sans clause ORDER BY, LIMIT, FOR UPDATE ou
FOR 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.
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 UPDATE et FOR SHARE ne peuvent pas être spécifiés dans un
résultat EXCEPT ou pour une entrée d'un
EXCEPT.
Clause ORDER BY
La clause optionnelle ORDER BY a la
forme générale :
ORDER BY expression [ ASC | DESC | USING opérateur ] [, ...]
expression
est le nom ou le
numéro ordinal d'une colonne en sortie (élément de la liste
SELECT
) ou une
expression quelconque formée à partir des valeurs des colonnes en
entrée.
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.
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. 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.
La valeur NULL est considérée supérieure à toute autre valeur. En
d'autres termes, avec un ordre de tri ascendant, les valeurs NULL
sont triées à la fin et avec un ordre de tri descendant, elles
sont triées au début.
Les données de chaînes de caractères sont triées suivant l'ordre
spécifique à la locale, ordre établi au moment de la création du
groupe de bases de données.
Clause DISTINCT
Si DISTINCT est spécifié, toutes les
lignes dupliquées sont supprimées de l'ensemble de résultats (une
ligne est conservée pour chaque groupe de lignes dupliquées).
ALL spécifie le contraire : toutes les
lignes sont conservées ; c'est la valeur par défaut.
DISTINCT ON (
expression
[, ...] ) ne conserve
que la première ligne de chaque ensemble pour lesquels il y a
identité des expressions. Les expressions DISTINCT ON sont interprétées en utilisant les
mêmes règles que pour ORDER BY (voir
ci-dessus). La « première
ligne » de chaque ensemble n'est pas prévisible sauf
si ORDER BY est utilisé. Par exemple,
SELECT DISTINCT ON (emplacement) emplacement, heure, rapport
FROM rapports_meteo
ORDER BY emplacement, heure DESC;
récupère le rapport météo le plus récent de chaque emplacement.
Si ORDER BY n'est pas utilisé pour
forcer l'ordre descendant des valeurs heure de chaque
emplacement, le rapport est ordonné suivant des temps aléatoires.
Le(s) expression(s) DISTINCT ON
doi(ven)t correspondre à l'ordre des expression ORDER BY. La clause ORDER
BY contient des expressions supplémentaires qui déterminent
la précédence désirée des lignes à l'intérieur de chaque groupe
DISTINCT ON.
Clause LIMIT
La clause LIMIT est constituée de deux
sous-clauses indépendantes :
LIMIT { nombre | ALL }
OFFSET début
nombre
spécifie le nombre
maximum de lignes à renvoyer alors que
début
spécifie le nombre de lignes à
passer avant de commencer à renvoyer des lignes. Lorsque les deux
clauses sont spécifiées,
début
lignes sont passées avant de
commencer à compter les
nombre
lignes à renvoyer.
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.
Clause FOR UPDATE/FOR SHARE
La clause FOR UPDATE a la forme :
FOR UPDATE [ OF nom_table [, ...] ] [ NOWAIT ]
La clause liée, FOR SHARE, a la forme :
FOR SHARE [ OF nom_table [, ...] ] [ NOWAIT ]
FOR UPDATE verrouille pour modification
les lignes récupérées par l'instruction
SELECT
. Cela les empêche d'être
modifiées ou supprimées par les autres transactions jusqu'à la
fin de la transaction en cours. Les autres transactions qui
tentent des
UPDATE
,
DELETE
ou
SELECT FOR UPDATE
sur ces lignes sont bloquées jusqu'à la fin de la transaction
courante. De plus, si un
UPDATE
,
DELETE
ou
SELECT FOR UPDATE
a déjà
verrouillé une ligne ou un ensemble de lignes à partir d'une
autre transaction,
SELECT FOR
UPDATE
attend la fin de l'autre transaction puis
verrouille et renvoie la ligne modifiée (ou aucune ligne si elle
a été supprimée). Pour plus d'informations, voir Chapitre 12,
Contrôle d'accès simultané.
Pour éviter à l'opération d'attendre la validation des autres
transactions, on utilise l'option NOWAIT.
SELECT FOR
UPDATE NOWAIT
rapporte une erreur si une ligne
sélectionnée ne peut pas être verrouillée immédiatement. Il n'y a
pas d'attente. NOWAIT s'applique
seulement au(x) verrou(x) niveau ligne -- le verrou niveau table
ROW SHARE est toujours pris de façon
ordinaire (voir Chapitre 12,
Contrôle d'accès simultané). L'option NOWAIT de LOCK peut toujours être utilisée pour acquérir
le verrou niveau table sans attendre.
FOR SHARE a un comportement similaire.
La différence se situe dans le type de verrou acquis.
Contrairement à FOR UPDATE qui pose un
verrou exclusif, FOR SHARE pose un
verrou partagé sur chaque ligne récupérée. Un verrou partagée
bloque les instructions
UPDATE
,
DELETE
ou
SELECT FOR UPDATE
des
transaction concurrentes accédant à ces lignes, mais il
n'interdit pas les
SELECT FOR
SHARE
.
Si des tables particulières sont nommées dans les clauses
FOR UPDATE et FOR
SHARE, alors seules les lignes provenant de ces tables sont
verrouillées ; toute autre table utilisée dans le
SELECT
est simplement lue. Une
clause FOR UPDATE ou FOR SHARE sans liste de tables affecte toute les
tables utilisées dans la commande. Si FOR
UPDATE ou FOR SHARE 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.
Plusieurs clauses FOR UPDATE et
FOR SHARE 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 les clauses FOR
UPDATE et FOR SHARE, alors elle est
traitée comme un simple FOR UPDATE. 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.
FOR UPDATE et FOR
SHARE 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'aggrégats.
Attention
Évitez de verrouiller une ligne puis de la modifier après un
nouveau point de sauvegarde ou après un bloc d'exception
PL/pgSQL. L'annulation
suivante pourrait causer la perte du verrou. Par exemple :
BEGIN;
SELECT * FROM ma_table WHERE cle = 1 FOR UPDATE;
SAVEPOINT s;
UPDATE ma_table SET ... WHERE cle = 1;
ROLLBACK TO s;
Après le
ROLLBACK
, la ligne est
réellement déverrouillée au lieu de retourner à son état
avant le point de sauvegarde. Ceci peut arriver si une ligne
verrouillée dans la transaction en cours est mise à jour ou
supprimée, ou si un verrou partagé est passé en verrou
exclusif : dans tous ces cas, l'état précédent du verrou est
oublié. Si la transation est ensuite annulée à un état entre
la commande de verrou initiale et la modification qui a
suivi, la ligne n'apparaîtra plus verrouillée. Ceci est une
déficience de l'implémentation qui sera corrigée dans une
prochaine version de PostgreSQL™.
Attention
Il est possible qu'une commande
SELECT
qui utilise
simultanément les clauses LIMIT et
FOR UPDATE/SHARE retourne moins de
lignes que le nombre spécifié par LIMIT. En effet, LIMIT est appliqué le premier. La commande
sélectionne le nombre de lignes spécifiées, mais peut être
bloquée en essayant d'obtenir un verrou sur l'une ou l'autre
de ces lignes. Lorsque le SELECT est
débloqué, la ligne peut avoir été supprimée ou modifiée de
telle sorte qu'elle ne remplisse plus les conditions imposées
par la clause WHERE. Dans ce cas,
elle n'est pas retournée.
Exemples
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
Compatibilité
L'instruction
SELECT
est évidemment compatible avec le standard SQL. Mais il y a des
extensions et quelques fonctionnalités manquantes.
Clauses FROM omises
PostgreSQL™ autorise
l'omission de la clause FROM. Cela
permet par exemple de calculer le résultat d'expressions simples
:
SELECT 2+2;
?column?
----------
4
D'autres bases de données SQL
interdisent ce comportement, sauf à introduire une table
virtuelle d'une seule ligne sur laquelle exécuter la commande
SELECT
.
S'il n'y a pas de clause FROM, la
requête ne peut pas référencer les tables de la base de données.
La requête suivante est, ainsi, invalide :
SELECT distributors.* WHERE distributors.name = 'Westward';
Les versions antérieures à PostgreSQL™ 8.1 acceptaient les
requêtes de cette forme en ajoutant une entrée implicite à la
clause FROM pour chaque table
référencée. Ce n'est plus le comportement par défaut, d'une part
parce qu'il n'est pas compatible avec le standard SQL et, d'autre
part, parce que considéré par beaucoup comme générateur
d'erreurs. Pour des raisons de compatibilité avec les
applications utilisant ce comportement, la variable de
configuration add_missing_from
peut toujours être activée.
Mot clé AS
Dans le SQL standard, le mot clé AS est
optionnel et peut être omis sans affecter la signification.
L'analyseur PostgreSQL™
requiert ce mot clé lors du renommage des colonnes en sortie
parce que les fonctionnalités d'extension de type créent des
ambiguïtés d'analyse s'il est omis. AS
est néanmoins optionnel pour les éléments FROM.
Espace logique disponible pour GROUP BY
et ORDER BY
Dans le standard SQL-92, une clause ORDER
BY ne peut utiliser que les noms ou numéros des colonnes en
sortie, une clause GROUP BY que des
expressions fondées sur les noms de colonnes en entrée.
PostgreSQL™ va plus loin,
puisqu'il autorise chacune de ces clauses à utiliser également
l'autre possibilité. En cas d'ambiguïté, c'est l'interprétation
du standard qui prévaut. PostgreSQL™ autorise aussi
l'utilisation d'expressions quelconques dans les deux clauses.
Les noms apparaissant dans ces expressions sont toujours
considérés comme nom de colonne en entrée, pas en tant que nom de
colonne du résultat.
SQL:1999 et suivant utilisent une définition légèrement
différente, pas totalement compatible avec le SQL-92. Néanmoins,
dans la plupart des cas, PostgreSQL™ interprète une expression
ORDER BY ou GROUP
BY en suivant la norme SQL:1999.
Clauses non standard
Les clauses DISTINCT ON, LIMIT et OFFSET ne sont
pas définies dans le standard SQL.
|