4.2. Expressions de valeurs

Les expressions de valeurs sont utilisées dans une grande variété de contextes, tels que dans la liste cible d'une commande SELECT, dans les nouvelles valeurs de colonnes d'une commande INSERT ou UPDATE, ou dans les conditions de recherche d'un certain nombre de commandes. Le résultat d'une expression de valeurs est quelque fois appelé scalaire, pour le distinguer du résultat d'une expression de table (qui est une table). Les expressions de valeurs sont aussi appelées des expressions scalaires (voire même simplement des expressions). La syntaxe d'expression permet le calcul des valeurs à partir de morceaux primitifs en utilisant les opérations arithmétiques, logiques, d'ensemble et autres.

Une expression de valeur fait partie des suivantes :

En plus de cette liste, il existe un certain nombre de constructions pouvant être classées comme une expression mais ne suivant aucune règle de syntaxe générale. Elles ont généralement la sémantique d'une fonction ou d'un opérateur et sont expliquées à l'emplacement approprié dans le Chapitre 9. Un exemple est la clause IS NULL.

Nous avons déjà discuté des constantes dans la Section 4.1.2. Les sections suivantes discutent des options restantes.

4.2.1. Références de colonnes

Une colonne peut être référencée avec la forme

correlation.nomcolonne

correlation est le nom d'une table (parfois qualifié par son nom de schéma) ou un alias d'une table définie au moyen de la clause FROM ou un des mots clés NEW ou OLD. (NEW et OLD peuvent seulement apparaître dans les règles de réécriture alors que les autres noms de corrélation peuvent être utilisés dans toute instruction SQL.) Le nom de corrélation et le point de séparation peuvent être omis si le nom de colonne est unique dans les tables utilisées par la requête courante. (Voir aussi Chapitre 7.)

4.2.2. Paramètres de position

Un paramètre de position est utilisé pour indiquer une valeur fournie en externe par une instruction SQL. Les paramètres sont utilisés dans des définitions de fonction SQL et dans les requêtes préparées. Quelques bibliothèques clients supportent aussi la spécification de valeurs de données séparément de la chaîne de commande SQL, auquel cas les paramètres sont utilisés pour référencer les valeurs de données en dehors. Le format d'une référence de paramètre est :

$numéro

Par exemple, considérez la définition d'une fonction dept comme

CREATE FUNCTION dept(text) RETURNS dept
    AS 'SELECT * FROM dept WHERE nom = $1'
    LANGUAGE SQL;

Ici, $1 sera remplacé par le premier argument de fonction lorsque la commande sera appelée.

4.2.3. Indices

Si une expression récupère une valeur de type tableau, alors un élément spécifique du tableau peut être extrait en écrivant

expression[indice]

ou des éléments adjacents (un << morceau de tableau >>) peuvent être extrait en écrivant

expression[indice_bas:
indice_haut]

(Ici, les crochets [ ] doivent apparaître littéralement.) Chaque indice est lui-même une expression, qui doit renvoyer une valeur entière.

En général, l'expression de type tableau doit être entre parenthèses mais celles-ci peuvent être omises lorsque l'expression à indicer est seulement une référence de colonne ou une position de paramètre. De plus, les indices multiples peuvent être concaténés lorsque le tableau original est multi-dimensionnel. Par exemple,

matable.colonnetableau[4]
matable.colonnes_deux_d[17][34]
$1[10:42]
(fonctiontableau(a,b))[42]

Les parenthèses dans ce dernier exemple sont requises. Voir la Section 8.10 pour plus d'informations sur les tableaux.

4.2.4. Sélection de champs

Si une expression récupère une valeur de type composé (type row), alors un champ spécifique de la ligne est extrait en écrivant

expression.nomchamp

En général, l'expression de ligne doit être entre parenthèses mais les parenthèses peuvent être omises lorsque l'expression à partir de laquelle se fait la sélection est seulement une référence de table ou un paramètre de position. Par exemple,

matable.macolonne
$1.unecolonne
(fonctionligne(a,b)).col3

(Donc, une référence de colonne qualifiée est réellement un cas spécial de syntaxe de sélection de champ.)

4.2.5. Appels d'opérateurs

Il existe trois syntaxes possibles pour l'appel d'un opérateur :

expression opérateur expression (opérateur binaire préfixe)
opérateur expression (opérateur unaire préfixe)
expression opérateur (opérateur unaire suffixe)

où le jeton opérateur suit les règles de syntaxe de la Section 4.1.3, ou est un des mots clés AND, OR et NOT, ou est un nom d'opérateur qualifié de la forme

OPERATOR(schema.nomopérateur)

Quel opérateur particulier existe et est-il unaire ou binaire dépend des opérateurs définis par le système ou l'utilisateur. Le Chapitre 9 décrit les opérateurs internes.

4.2.6. Appels de fonctions

La syntaxe pour un appel de fonction est le nom d'une fonction (qualifié ou non du nom du schéma) suivi par sa liste d'arguments entre parenthèses :

fonction
([expression [,
expression ... ]] )

Par exemple, ce qui suit calcule la racine carré de 2 :

sqrt(2)

La liste des fonctions intégrées est dans le Chapitre 9. D'autres fonctions pourraient être ajoutées par l'utilisateur.

4.2.7. Expressions d'agrégat

Une expression d'agrégat représente l'application d'une fonction d'agrégat à travers les lignes sélectionnées par une requête. Une fonction d'agrégat réduit les nombres entrés en une seule valeur de sortie, comme la somme ou la moyenne des valeurs en entrée. La syntaxe d'une expression d'agrégat est une des suivantes :

nom_agregat (expression)
nom_agregat (ALL
expression)
nom_agregat (DISTINCT
expression)
nom_agregat ( * )

nom_agregat est un agrégat précédemment défini (parfois qualifié d'un nom de schéma) et expression est toute expression de valeur qui ne contient pas lui-même une expression d'agrégat.

La première forme d'expression d'agrégat appelle l'agrégat pour toutes les lignes en entrée pour lesquelles l'expression donnée ne trouve pas une valeur NULL. (En fait, c'est à la fonction d'agrégat de savoir si elle doit ignorer ou non les valeurs NULL... mais toutes les fonctions standards le font.) La seconde forme est identique à la première car ALL est par défaut. La troisième forme implique l'agrégat pour toutes les valeurs de l'expression non NULL et distinctes trouvées dans les lignes en entrée. La dernière forme appelle l'agrégat une fois pour chaque ligne en entrée qu'elle soit NULL ou non ; comme aucune valeur particulière en entrée n'est spécifiée, c'est généralement utile pour la fonction d'agrégat count().

Par exemple, count(*) trouve le nombre total de lignes en entrée ; count(f1) récupère le nombre de lignes en entrée pour lesquelles f1 n'est pas NULL ; count(distinct f1) retrouve le nombre de valeurs distinctes non NULL de f1.

Les fonctions d'agrégat prédéfinies sont décrites dans la Section 9.15. D'autres fonctions d'agrégat pourraient être ajoutées par l'utilisateur.

Une expression d'agrégat pourrait apparaître dans la liste de résultat ou dans la clause HAVING d'une commande SELECT. Elle est interdite dans d'autres clauses, telles que WHERE, parce que ces clauses sont logiquement évaluées avant que les résultats des agrégats soient formés.

Lorsqu'une expression d'agrégat apparaît dans une sous-requête (voir la Section 4.2.9 et la Section 9.16), l'agrégat est normalement évalué sur les lignes de la sous-requête. Mais, une exception arrive si l'argument de l'agrégat contient seulement des niveaux externes de variables : ensuite, l'agrégat appartient au niveau externe le plus proche et est évalué sur les lignes de cette requête. L'expression de l'agrégat en un tout est une référence externe pour la sous-requête dans laquelle il apparaît et agit comme une constante sur toute évaluation de cette requête. La restriction apparaissant seulement dans la liste de résultat ou dans la clause HAVING s'applique avec respect du niveau de requête auquel appartient l'agrégat.

4.2.8. Conversions de type

Une conversion de type spécifie une conversion à partir d'un type de données en un autre. PostgreSQL accepte deux syntaxes équivalentes pour les conversions de type :

CAST ( expression AS type )
expression::type

La syntaxe CAST est conforme à SQL ; la syntaxe avec :: est historique dans PostgreSQL usage.

Lorsqu'une conversion est appliquée à une expression de valeur pour un type connu, il représente une conversion de type à l'exécution. Cette conversion réussira seulement si une fonction convenable de conversion de type est disponible. Notez que ceci est subtilement différent de l'utilisation de conversion avec des constantes, comme indiqué dans la Section 4.1.2.4. Une conversion appliquée à une chaîne littérale représente l'affectation initiale d'un type pour une valeur constante littérale, et donc cela réussira pour tout type (si le contenu de la chaîne littérale est une syntaxe acceptée en entrée pour le type de donnée).

Une conversion de type explicite pourrait être habituellement omise s'il n'y a pas d'ambiguïté sur le type qu'une expression de valeur pourrait produire (par exemple, lorsqu'elle est affectée à une colonne de table) ; le système appliquera automatiquement une conversion de type dans de tels cas. Néanmoins, la conversion automatique est réalisée seulement pour les conversions marquées << OK pour application implicite >> dans les catalogues système. D'autres conversions peuvent être appelées avec la syntaxe de conversion explicite. Cette restriction a pour but d'empêcher l'application silencieuse de conversions surprenantes.

Il est aussi possible de spécifier une conversion de type en utilisant une syntaxe de type fonction :

nomtype ( expression )

Néanmoins, ceci fonctionne seulement pour les types dont les noms sont aussi valides en tant que noms de fonctions. Par exemple, double precision ne peut pas être utilisé de cette façon mais son équivalent float8 le peut. De même, les noms interval, time et timestamp peuvent seulement être utilisés de cette façon s'ils sont entre des guillemets doubles à cause des conflits de syntaxe. Du coup, l'utilisation de la syntaxe de conversion du style fonction amène à des inconsistances et devrait probablement être évitée dans les nouvelles applications. (La syntaxe style fonction est en fait seulement un appel de fonction. Quand un des deux standards de syntaxe de convertion est utilisé pour faire une conversion à l'exécution, elle appellera en interne une fonction enregistrée pour réaliser la conversion. Par convention, ces fonctions de conversion ont le même nom que leur type de sortie et, du coup, la << syntaxe style fonction >> n'est rien de plus qu'un appel direct à la fonction de conversion sous-jacente. Évidemment, une application portable ne devrait pas s'y fier.)

4.2.9. Sous-requêtes scalaires

Une sous-requête scalaire est une requête SELECT ordinaire entre parenthèses renvoyant exactement une ligne avec une colonne. (Voir le Chapitre 7 pour plus d'informations sur l'écriture des requêtes.) La requête SELECT est exécutée et la seule valeur renvoyée est utilisée dans l'expression de valeur englobante. C'est une erreur d'utiliser une requête qui renvoie plus d'une ligne ou plus d'une colonne comme requête scalaire. (Mais si, lors d'une exécution particulière, la sous-requête ne renvoie pas de lignes, alors il n'y a pas d'erreur ; le résultat scalaire est supposé NULL.) La sous-requête peut référencer des variables de la requête englobante, qui agiront comme des constantes durant toute évaluation de la sous-requête. Voir aussi Section 9.16 pour d'autres expressions impliquant des sous-requêtes.

Par exemple, ce qui suit trouve la ville disposant de la population la plus importante dans chaque état :

SELECT nom, (SELECT max(pop) FROM villes WHERE villes.etat = etat.nom)
    FROM etats;

4.2.10. Constructeurs de tableaux

Un constructeur de tableau est une expression qui construit une valeur de tableau à partir de valeurs de ses membres. Un constructeur de tableau simple utilise le mot clé ARRAY, un crochet ouvrant [, une ou plusieurs expressions (séparées par des virgules) pour les valeurs des éléments du tableau et finalement un crochet fermant ]. Par exemple :

SELECT ARRAY[1,2,3+4];
  array
---------
 {1,2,7}
(1 row)

Le type d'élément du tableau est le type commun des expressions des membres, déterminé en utilisant les mêmes règles que pour les constructions UNION ou CASE (voir Section 10.5).

Les valeurs de tableaux multidimensionnels peuvent être construits par des constructeurs de tableaux imbriqués. Pour les constructeurs internes, le mot clé ARRAY pourrait être omis. Par exemple, ces expressions produisent le même résultat :

SELECT ARRAY[ARRAY[1,2], ARRAY[3,4]];
     array
---------------
 {{1,2},{3,4}}
(1 row)

SELECT ARRAY[[1,2],[3,4]];
     array
---------------
 {{1,2},{3,4}}
(1 row)

Comme les tableaux multidimensionnels doivent être rectangulaires, les constructeurs internes du même niveau doivent produire des sous-tableaux de dimensions identiques.

Les éléments d'un constructeur de tableau multidimensionnel peuvent être tout ce qui récupère un tableau du bon type, pas seulement une construction de sous-ARRAY. Par exemple :

CREATE TABLE arr(f1 int[], f2 int[]);

INSERT INTO arr VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]);

SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM arr;
                     array
------------------------------------------------
 {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}}
(1 row)

Il est aussi possible de construire un tableau à partir des résultats d'une sous-requête. Avec cette forme, le constructeur de tableau est écrit avec le mot clé ARRAY suivi par une sous-requête entre parenthèses (et non pas des crochets). Par exemple :

SELECT ARRAY(SELECT oid FROM pg_proc WHERE proname LIKE 'bytea%');
                          ?column?
-------------------------------------------------------------
 {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31}
(1 row)

La sous-requête doit renvoyer une seule colonne. Le tableau à une dimension résultant aura un élément pour chaque ligne dans le résultat de la sous-requête, avec un type élément correspondant à celui de la colonne en sortie de la sous-requête.

Les indices d'une valeur de tableau construit avec ARRAY commencent toujours à un. Pour plus d'informations sur les tableaux, voir la Section 8.10.

4.2.11. Règles d'évaluation des expressions

L'ordre d'évaluation des sous-expressions n'est pas défini. En particulier, les entrées d'un opérateur ou d'une fonction ne sont pas nécessairement évaluées de la gauche vers la droite our dans un autre ordre fixé.

De plus, si le résultat d'une expression peut être déterminé par l'évaluation de quelques parties de celui-ci, alors d'autres sous-expressions devraient ne pas être évaluées du tout. Par exemple, si vous écrivez :

SELECT true OR unefonction();

alors unefonction() pourrait (probablement) ne pas être appelée du tout. Pareil dans le cas suivant :

SELECT somefunc() OR true;

Notez que ceci n'est pas identique au << court-circuitage >> de gauche à droite des opérateurs booléens utilisé par certains langages de programmation.

En conséquence, il est déconseillé d'utiliser des fonctions ayant des effets de bord dans une partie des expressions complexes. Il est particulièrement dangereux de se fier aux effets de bord ou à l'ordre d'évaluation dans les clauses WHERE et HAVING, car ces clauses sont reproduites de nombreuses fois lors du développement du plan d'exécution. Les expressions booléennes (combinaisons AND/OR/NOT) dans ces clauses pourraient être réorganisées de toute autre façon que celles autorisées dans l'algèbre booléenne.

Quand il est essentiel de forcer l'ordre d'évaluation, une construction CASE (voir Section 9.12) pourrait être utilisée. Par exemple, c'est une façon, non sûre, d'essayer d'éviter une division par zéro dans une clause WHERE :

SELECT ... WHERE x <> 0 AND y/x > 1.5;

Mais ceci est sûr :

SELECT ... WHERE CASE WHEN x <> 0 THEN y/x > 1.5 ELSE false END;

Une construction CASE utilisée de cette façon déjouera les tentatives d'optimisation, donc cela ne sera fait que si nécessaire. (Dans cet exemple particulier, il serait sans doute mieux de contourner le problème en écrivant y > 1.5*x.)