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 quelquefois 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 peut être :
Une constante ou une valeur littérale.
Une référence de colonne.
Une référence de paramètre de position, dans le corps d'une définition de fonction ou d'instruction préparée.
Une expression indicée.
Une expression de sélection de champs.
Un appel d'opérateur.
Un appel de fonction.
Une expression d'agrégat.
Un appel de fonction window.
Une conversion de type.
Une sous-requête scalaire.
Un constructeur de tableau.
Un constructeur de ligne.
Toute expression de tableau entre parenthèses, utile pour grouper des sous-expressions et surcharger la précédence.
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, Fonctions et opérateurs. Un exemple est la clause IS NULL.
Nous avons déjà discuté des constantes dans la Section 4.1.2, « Constantes ». Les sections suivantes discutent des options restantes.
Une colonne peut être référencée avec la forme
correlation.nom_colonne
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. 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 le Chapitre 7, Requêtes).
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 référence la valeur du premier argument de la fonction à chaque appel de cette commande.
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 contenir une valeur entière.
En général, l'expression de type tableau doit être entre parenthèses mais ces dernières 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 :
ma_table.colonnetableau[4] ma_table.colonnes_deux_d[17][34] $1[10:42] (fonctiontableau(a,b))[42]
Dans ce dernier exemple, les parenthèses sont requises. Voir la Section 8.14, « Tableaux » pour plus d'informations sur les tableaux.
Si une expression récupère une valeur de type composite (type row), alors un champ spécifique de la ligne est extrait en écrivant
expression.nom_champ
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 :
ma_table.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. Un cas spécial important revient à extraire un champ de la colonne de type composite d'une table :
(colcomposite).unchamp (matable.colcomposite).unchamp
Les parenthèses sont requises ici pour montrer que colcomposite est un nom de colonne, et non pas un nom de table, ou que matable est un nom de table, par un nom de schéma dans le deuxième cas.
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, « Opérateurs », ou est un des mots clés AND, OR et NOT, ou est un nom d'opérateur qualifié de la forme
OPERATOR(schema.nom_operateur)
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, Fonctions et opérateurs décrit les opérateurs internes.
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 :
nom_fonction([expression [,expression ...]] )
Par exemple, ce qui suit calcule la racine carré de 2 :
sqrt(2)
La liste des fonctions intégrées se trouve dans le Chapitre 9, Fonctions et opérateurs. D'autres fonctions pourraient être ajoutées par l'utilisateur.
En option, les arguments peuvent avoir leur nom attaché. Voir Section 4.3, « Fonctions appelantes » pour les détails.
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 [ , ... ] [ clause_order_by ] ) nom_agregat (ALL expression [ , ... ] [ clause_order_by ] ) nom_agregat (DISTINCT expression [ , ... ] [ clause_order_by ] ) nom_agregat ( * )
où nom_agregat est un agrégat précédemment défini (parfois qualifié d'un nom de schéma), expression est toute expression de valeur qui ne contient pas lui-même une expression d'agrégat ou un appel à une fonction de fenêtrage. order_by_clause est une clause ORDER BY optionnelle comme décrite ci-dessous.
La première forme d'expression d'agrégat appelle l'agrégat une fois pour chaque ligne en entrée. La seconde forme est identique à la première car ALL est ajouté par défaut. La troisième forme fait appel à l'agrégat une fois pour chaque valeur distincte de l'expression (ou ensemble distinct de valeurs, pour des expressions multiples) trouvée dans les lignes en entrée. La dernière forme appelle l'agrégat une fois pour chaque ligne en entrée ; 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(*).
La plupart des fonctions d'agrégats ignorent les entrées NULL, pour que les lignes pour lesquelles une ou plusieurs expressions renvoient NULL soient disqualifiées. Ceci peut être considéré vrai, sauf indication contraire pour tous les agrégats internes.
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, car la fonction count ignore les valeurs NULL ; et count(distinct f1) retrouve le nombre de valeurs distinctes non NULL de f1.
D'habitude, les lignes en entrée sont passées à la fonction d'agrégat dans un ordre non spécifié. Dans la plupart des cas, cela n'a pas d'importance. Par exemple, min donne le même résultat quelque soit l'ordre dans lequel il reçoit les données. Néanmoins, certaines fonctions d'agrégat (telle que array_agg et string_agg) donnent un résultat dépendant de l'ordre des lignes en entrée. Lors de l'utilisation de ce type d'agrégat, la clause clause_order_by peut être utilisée pour préciser l'ordre de tri désiré. La clause clause_order_by a la même syntaxe que la clause ORDER BY d'une requête, qui est décrite dans Section 7.5, « Tri des lignes », sauf que ses expressions sont toujours des expressions simples et ne peuvent pas être des noms de colonne en sortie ou des numéros. Par exemple :
SELECT array_agg(a ORDER BY b DESC) FROM table;
Lors de l'utilisation de fonctions d'agrégat à plusieurs arguments, la clause ORDER BY arrive après tous les arguments de l'agrégat. Par exemple, il faut écrire ceci :
SELECT string_agg(a, ',' ORDER BY a) FROM table;
et non pas ceci :
SELECT string_agg(a ORDER BY a, ',') FROM table; -- incorrect
Ce dernier est syntaxiquement correct mais il concerne un appel à une fonction d'agrégat à un seul argument avec deux clés pour le ORDER BY (le deuxième étant inutile car il est constant).
Si DISTINCT est indiqué en plus d'une clause_order_by, alors toutes les expressions de l'ORDER BY doivent correspondre aux arguments de l'agrégat ; autrement dit, vous ne pouvez pas trier sur une expression qui n'est pas incluse dans la liste DISTINCT.
La possibilité de spécifier à la fois DISTINCT et ORDER BY dans une fonction d'agrégat est une extension de PostgreSQL™.
Les fonctions d'agrégat prédéfinies sont décrites dans la Section 9.18, « Fonctions d'agrégat ». 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 ne soient formés.
Lorsqu'une expression d'agrégat apparaît dans une sous-requête (voir la Section 4.2.10, « Sous-requêtes scalaires » et la Section 9.20, « Expressions de sous-requêtes »), l'agrégat est normalement évalué sur les lignes de la sous-requête. Mais, une exception arrive si les arguments de l'agrégat contiennent 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.
Un appel de fonction window représente l'application d'une fonction de type agrégat sur une portion des lignes sélectionnées par une requête. Contrairement aux appels de fonction d'agrégat standard, ce n'est pas lié au groupement des lignes sélectionnées en une seule ligne résultat -- chaque ligne reste séparée dans les résultats. Néanmoins, la fonction window est capable de parcourir toutes les lignes qui font partie du groupe de la ligne courante d'après la spécification du groupe (liste PARTITION BY) de l'appel de la fonction window. La syntaxe d'un appel de fonction window est une des suivantes :
nom_fonction ([expression [, expression ... ]]) OVER ( définition_window ) nom_fonction ([expression [, expression ... ]]) OVER nom_window nom_fonction ( * ) OVER ( définition_window ) nom_fonction ( * ) OVER nom_window
où définition_window a comme syntaxe :
[ nom_window_existante ] [ PARTITION BY expression [, ...] ] [ ORDER BY expression [ ASC | DESC | USING opérateur ] [ NULLS { FIRST | LAST } ] [, ...] ] [ clause_frame ]
et la clause clause_frame optionnelle fait partie de :
[ RANGE | ROWS ] début_frame [ RANGE | ROWS ] BETWEEN début_frame AND fin_frame
avec début_frame et fin_frame pouvant faire partie de
UNBOUNDED PRECEDING valeur PRECEDING CURRENT ROW valeur FOLLOWING UNBOUNDED FOLLOWING
Ici, expression représente toute expression de valeur qui ne contient pas elle-mêle d'appel à des fonctions window. Les listes PARTITION BY et ORDER BY ont essentiellement la même syntaxe et la même sémantique que les clauses GROUP BY et ORDER BY de la requête complète, sauf que leur expressions sont toujours seulement des expressions et ne peuvent pas être des noms ou des numéros de colonnes en sortie. nom_window est une référence à la spécification d'une window nommée, définie dans la clause WINDOW de la requête. Les spécifications window nommées sont habituellement référencées avec OVER nom_window, mais il est aussi possible d'écrire un nom de window entre parenthèses, puis de fournir en option une clause de tri et/ou une clause frame (le window reférencé ne doit pas avoir ces clauses si elles sont fournies ici). Cette dernière syntaxe suit les même règles que la modification d'un nom de window existant dans une clause WINDOW ; voir la page de référence de SELECT(7) pour les détails.
La clause clause_frame indique l'ensemble de lignes constituant le frame window, pour les fonctions window qui agissent sur le frame et non pas sur la partition entière. Si fin_frame est omis, sa valeur par défaut est 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 fin_frame ne peut pas apparaître avant début_frame -- par exemple, RANGE BETWEEN CURRENT ROW AND valeur PRECEDING n'est pas autorisé. L'option de frame par défaut est RANGE UNBOUNDED PRECEDING, qui est identique à RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ; cela configure la frame à toutes les lignes à partir du début de la partition jusqu'à la ligne actuelle du prochain dans l'ordre du ORDER BY (ce qui signifie toutes les lignes si la clause ORDER BY est absente). En général, UNBOUNDED PRECEDING signifie que la frame commence avec la première ligne de la partition et, de façon similaire, UNBOUNDED FOLLOWING signifie que la frame se termine avec la dernière ligne de la partition (quel que soit le mode, RANGE ou ROWS. Dans le mode ROWS, CURRENT ROW signifie que la frame commence ou finit avec la ligne actuelle ; mais dans le mode RANGE, cela signifie que la frame commence ou finit avec le premier ou le prochain élément à partir de la ligne actuel dans l'ordre indiqué par la clause ORDER BY. Les cas valeur PRECEDING et valeur FOLLOWING sont actuellement seulement autorisés dans le mode ROWS. Ils indiquent que la frame commence ou finit avec la ligne qui se trouve à ce nombre de lignes avant ou après la ligne actuelle. valeur doit être une expression entière ne contenant aucune variable, fonction d'agrégat ou fonction de fenêtrage. La valeur ne doit pas être NULL ou négative. Par contre, elle peut valoir zéro, ce qui a pour effet de sélectionner la ligne actuelle.
Les fonctions window internes sont décrites dans Tableau 9.44, « Fonctions Window généralistes ». D'autres fonctions window peuvent être ajoutées par l'utilisateur. De plus, toute fonction d'agrégat interne ou définie par l'utilisateur peut être utilisée comme fonction window.
Les syntaxes utilisant * sont utilisées pour appeler des fonctions d'agrégats sans paramètres en tant que fonctions window. Par exemple : count(*) OVER (PARTITION BY x ORDER BY y). * n'est habituellement pas utilisé pour les fonctions window qui ne sont pas des agrégats. Les fonctions window agrégats, contrairement aux fonctions d'agrégats normales, n'autorisent pas l'utilisation de DISTINCT ou ORDER BY dans la liste des arguments de la fonction.
Les appels de fonctions window sont autorisés seulement dans la liste SELECT et dans la clause ORDER BY de la requête.
Il existe plus d'informations sur les fonctions de fenêtrages dans le Section 3.5, « Fonctions window », Section 9.19, « Fonctions Window » et dans le Section 7.2.4, « Traitement de fonctions Window ».
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™.
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 opération convenable de conversion de type a été définie. Notez que ceci est subtilement différent de l'utilisation de conversion avec des constantes, comme indiqué dans la Section 4.1.2.7, « Constantes d'autres types ». 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 :
nom_type ( 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.
La syntaxe style fonction est en fait seulement un appel de fonction. Quand un des deux standards de syntaxe de conversion 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. Pour plus d'informations, voir CREATE CAST(7).
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, Requêtes 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 la Section 9.20, « Expressions de sous-requêtes » 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;
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 liste d'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)
Par défaut, 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 la Section 10.5, « Constructions UNION, CASE et constructions relatives »). Vous pouvez surcharger ceci en convertissant explicitement le constructeur de tableau vers le type désiré. Par exemple :
SELECT ARRAY[1,2,22.7]::integer[]; array ---------- {1,2,23} (1 row)
Ceci a le même effet que la conversion de chaque expression vers le type d'élément du tableau individuellement. Pour plus d'informations sur les conversions, voir Section 4.2.9, « Conversions de type ».
Les valeurs de tableaux multidimensionnels peuvent être construits par des constructeurs de tableaux imbriqués. Pour les constructeurs internes, le mot clé ARRAY peut ê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. Toute conversion appliquée au constructeur ARRAY externe se propage automatiquement à tous les constructeurs internes.
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 d'un tableau imbriqué. Par exemple :
CREATE TABLE tab(f1 int[], f2 int[]); INSERT INTO tab VALUES (ARRAY[[1,2],[3,4]], ARRAY[[5,6],[7,8]]); SELECT ARRAY[f1, f2, '{{9,10},{11,12}}'::int[]] FROM tab; array ------------------------------------------------ {{{1,2},{3,4}},{{5,6},{7,8}},{{9,10},{11,12}}} (1 row)
Vous pouvez construire un tableau vide mais, comme il est impossible d'avoir un tableau sans type, vous devez convertir explicitement votre tableau vide dans le type désiré. Par exemple :
SELECT ARRAY[]::integer[]; array ------- {} (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.14, « Tableaux ».
Un constructeur de ligne est une expression qui construit une valeur de ligne (aussi appelée une valeur composite) à partir des valeurs de ses membres. Un constructeur de ligne consiste en un mot clé ROW, une parenthèse gauche, zéro ou plus d'une expression (séparées par des virgules) pour les valeurs des champs de la ligne, et finalement une parenthèse droite. Par exemple :
SELECT ROW(1,2.5,'ceci est un test');
Le mot clé ROW est optionnel lorsqu'il y a plus d'une expression dans la liste.
Un constructeur de ligne peut inclure la syntaxe rowvalue.*, qui sera étendue en une liste d'éléments de la valeur ligne, ce qui arrive lorsque la syntaxe .* est utilisée au niveau haut d'une liste SELECT. Par exemple, si la table t a les colonnes f1 et f2, elles sont identiques :
SELECT ROW(t.*, 42) FROM t; SELECT ROW(t.f1, t.f2, 42) FROM t;
Avant PostgreSQL™ 8.2, la syntaxe .* n'était pas étendue, pour que écrire ROW(t.*, 42) crée une ligne à deux champs dont le premier est une autre valeur de ligne. Le nouveau comportement est habituellement plus utile. Si vous avez besoin de l'ancien comportement de valeurs de ligne imbriquées, écrivez la valeur de ligne interne sans .*, par exemple ROW(t, 42).
Par défaut, la valeur créée par une expression ROW est d'un type d'enregistrement anonyme. Si nécessaire, il peut être converti en un type composite nommé -- soit le type de ligne d'une table soit un type composite créé avec CREATE TYPE AS. Une conversion explicite pourrait être nécessaire pour éviter une ambiguïté. Par exemple :
CREATE TABLE ma_table(f1 int, f2 float, f3 text); CREATE FUNCTION recup_f1(ma_table) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- Aucune conversion nécessaire parce que seul un recup_f1() existe SELECT recup_f1(ROW(1,2.5,'ceci est un test')); recup_f1 ---------- 1 (1 row) CREATE TYPE mon_typeligne AS (f1 int, f2 text, f3 numeric); CREATE FUNCTION recup_f1(mon_typeligne) RETURNS int AS 'SELECT $1.f1' LANGUAGE SQL; -- Maintenant, nous avons besoin d'une conversion -- pour indiquer la fonction à appeler: SELECT recup_f1(ROW(1,2.5,'ceci est un test')); ERROR: function recup_f1(record) is not unique SELECT recup_f1(ROW(1,2.5,'ceci est un test')::ma_table); getf1 ------- 1 (1 row) SELECT recup_f1(CAST(ROW(11,'ceci est un test',2.5) AS mon_typeligne)); getf1 ------- 11 (1 row)
Les constructeurs de lignes peuvent être utilisés pour construire des valeurs composites à stocker dans une colonne de table de type composite ou pour être passé à une fonction qui accepte un paramètre composite. De plus, il est possible de comparer deux valeurs de lignes ou pour tester une ligne avec IS NULL ou IS NOT NULL, par exemple
SELECT ROW(1,2.5,'ceci est un test') = ROW(1, 3, 'pas le même'); SELECT ROW(table.*) IS NULL FROM table; -- détecte toutes les lignes non NULL
Pour plus de détails, voir la Section 9.21, « Comparaisons de lignes et de tableaux ». Les constructeurs de lignes peuvent aussi être utilisés en connexion avec des sous-requêtes, comme discuté dans la Section 9.20, « Expressions de sous-requêtes ».
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 ou dans un autre ordre fixé.
De plus, si le résultat d'une expression peut être déterminé par l'évaluation de certaines parties de celle-ci, alors d'autres sous-expressions devraient ne pas être évaluées du tout. Par exemple, si vous écrivez :
SELECT true OR une_fonction();
alors une_fonction() pourrait (probablement) ne pas être appelée du tout. Pareil dans le cas suivant :
SELECT une_fonction() 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 d'une autre façon autorisée dans l'algèbre booléenne.
Quand il est essentiel de forcer l'ordre d'évaluation, une construction CASE (voir la Section 9.16, « Expressions conditionnelles ») peut ê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).