PostgreSQLLa base de données la plus sophistiquée au monde.
Documentation PostgreSQL 12.22 » Langage SQL » Syntaxe SQL » Expressions de valeurs

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 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 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 constante ;

  • une rĂ©fĂ©rence de colonne ;

  • une rĂ©fĂ©rence de la position d'un paramĂštre, 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 de fenĂȘtrage ;

  • une conversion de type ;

  • une expression de collationnement ;

  • une sous-requĂȘte scalaire ;

  • un constructeur de tableau ;

  • un constructeur de ligne ;

  • toute expression de valeur 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 au 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.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).

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 commandes 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 :

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

Dans cet exemple, $1 référence la valeur du premier argument de la fonction à chaque appel de cette commande.

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]

Des Ă©lĂ©ments adjacents (un « morceau de tableau Â») peuvent ĂȘtre extraits en Ă©crivant :

expression[indice_bas:indice_haut]

Les crochets [ ] doivent apparaĂźtre rĂ©ellement. Chaque indice est elle-mĂȘme une expression, qui sera arrondie Ă  la valeur entiĂšre la plus proche.

En gĂ©nĂ©ral, l'expression de type tableau doit ĂȘtre entre parenthĂšses, mais ces derniĂšres peuvent ĂȘtre omises lorsque l'expression utilisĂ©e comme indice est seulement une rĂ©fĂ©rence de colonne ou un paramĂštre de position. De plus, les indices multiples peuvent ĂȘtre concatĂ©nĂ©s lorsque le tableau original est multidimensionnel. 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.15 pour plus d'informations sur les tableaux.

4.2.4. SĂ©lection de champs

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

En fait, une rĂ©fĂ©rence de colonne qualifiĂ©e est 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, pas un nom de schéma dans le deuxiÚme cas.

Vous pouvez demander tous les champs d'une valeur composite en Ă©crivant .* :

(compositecol).*
    

Cette syntaxe se comporte diffĂ©remment suivant le contexte. Voir Section 8.16.5 pour plus de dĂ©tails.

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.nom_operateur)

Le fait qu'opĂ©rateur particulier existe et qu'il soit 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 :

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. D'autres fonctions pourraient ĂȘtre ajoutĂ©es par l'utilisateur.

Lors de l'exĂ©cution de requĂȘtes dans une base de donnĂ©es oĂč certains utilisateurs ne font pas confiance aux autres utilisateurs, observez quelques mesures de sĂ©curitĂ© disponibles dans Section 10.3 lors de l'appel de fonctions.

En option, les arguments peuvent avoir leur nom attachĂ©. Voir la Section 4.3 pour les dĂ©tails.

Note

Une fonction qui prend un seul argument de type composite peut aussi ĂȘtre appelĂ©e en utilisant la syntaxe de sĂ©lection de champ. Du coup, un champ peut ĂȘtre Ă©crit dans le style fonctionnel. Cela signifie que les notations col(table) et table.col sont interchangeables. Ce comportement ne respecte pas le standard SQL, mais il est fourni dans PostgreSQL, car il permet l'utilisation de fonctions Ă©mulant les « champs calculĂ©s Â». Pour plus d'informations, voir la Section 8.16.5.

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 [ , ... ] [ clause_order_by ] ) [ FILTER ( WHERE clause_filtre ) ]
nom_agregat (ALL expression [ , ... ] [ clause_order_by ] ) [ FILTER ( WHERE clause_filtre ) ]
nom_agregat (DISTINCT expression [ , ... ] [ clause_order_by ] ) [ FILTER ( WHERE clause_filtre ) ]
nom_agregat ( * ) [ FILTER ( WHERE clause_filtre ) ]
nom_agregat ( [ expression [ , ... ] ] ) WITHIN GROUP ( clause_order_by ) [ FILTER ( WHERE clause_filtre ) ]

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 elle-mĂȘme une expression d'agrĂ©gat ou un appel Ă  une fonction de fenĂȘtrage. Les clauses optionnelles clause_order_by et clause_filtre sont dĂ©crites 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 une clause active 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 quatriĂšme 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 derniĂšre forme est utilisĂ©e avec les agrĂ©gats Ă  ensemble triĂ© qui sont dĂ©crits ci-dessous.

La plupart des fonctions d'agrĂ©gats ignorent les entrĂ©es NULL, pour que les lignes qui renvoient une ou plusieurs expressions NULL soient disqualifiĂ©es. Ceci peut ĂȘtre considĂ©rĂ© comme vrai pour tous les agrĂ©gats internes sauf indication contraire.

Par exemple, count(*) trouve le nombre total de lignes en entrée, alors que count(f1) récupÚre le nombre de lignes en entrée pour lesquelles f1 n'est pas NULL. En effet, la fonction count ignore les valeurs NULL, mais 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 quel que soit l'ordre dans lequel il reçoit les donnĂ©es. NĂ©anmoins, certaines fonctions d'agrĂ©gat (telles 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 la Section 7.5, 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 exemple 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 de la clause 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.

Note

La possibilité de spécifier à la fois DISTINCT et ORDER BY dans une fonction d'agrégat est une extension de PostgreSQL.

Placer la clause ORDER BY dans la liste des arguments standards de l'agrĂ©gat, comme dĂ©crit jusqu'ici, est utilisĂ© pour un agrĂ©gat de type gĂ©nĂ©ral et statistique pour lequel le tri est optionnel. Il existe une sous-classe de fonctions d'agrĂ©gat appelĂ©e agrĂ©gat d'ensemble triĂ© pour laquelle la clause clause_order_by est requise, habituellement parce que le calcul de l'agrĂ©gat est seulement sensible Ă  l'ordre des lignes en entrĂ©e. Des exemples typiques d'agrĂ©gat avec ensemble triĂ© incluent les calculs de rang et de pourcentage. Pour un agrĂ©gat d'ensemble triĂ©, la clause clause_order_by est Ă©crite Ă  l'intĂ©rieur de WITHIN GROUP (...), comme indiquĂ© dans la syntaxe alternative finale. Les expressions dans clause_order_by sont Ă©valuĂ©es une fois par ligne en entrĂ©e, comme n'importe quel argument d'un agrĂ©gat, une fois triĂ©es suivant la clause clause_order_by, et envoyĂ©es Ă  la fonction en tant qu'arguments en entrĂ©e. (Ceci est contraire au cas de la clause clause_order_by en dehors d'un WITHIN GROUP , qui n'est pas traitĂ© comme argument de la fonction d'agrĂ©gat.) Les expressions d'argument prĂ©cĂ©dant WITHIN GROUP, s'il y en a, sont appelĂ©es des arguments directs pour les distinguer des arguments agrĂ©gĂ©s listĂ©s dans clause_order_by. Contrairement aux arguments normaux d'agrĂ©gats, les arguments directs sont Ă©valuĂ©s seulement une fois par appel d'agrĂ©gat et non pas une fois par ligne en entrĂ©e. Cela signifie qu'ils peuvent contenir des variables seulement si ces variables sont regroupĂ©es par GROUP BY ; cette restriction Ă©quivaut Ă  des arguments directs qui ne seraient pas dans une expression d'agrĂ©gat. Les arguments directs sont typiquement utilisĂ©s pour des fractions de pourcentage, qui n'ont de sens qu'en tant que valeur singuliĂšre par calcul d'agrĂ©gat. La liste d'arguments directs peut ĂȘtre vide ; dans ce cas, Ă©crivez simplement (), et non pas (*). (PostgreSQL accepte actuellement les deux Ă©critures, mais seule la premiĂšre est conforme avec le standard SQL.)

Voici un exemple d'appel d'agrĂ©gat Ă  ensemble triĂ© :

SELECT percentile_cont(0.5) WITHIN GROUP (ORDER BY revenu) FROM proprietes;
 percentile_cont
-----------------
           50489
    

qui obtient le 50e pourcentage ou le mĂ©dian des valeurs de la colonne revenu de la table proprietes. Ici, 0.5 est un argument direct ; cela n'aurait pas de sens si la fraction de pourcentage Ă©tait une valeur variant suivant les lignes.

Si la clause FILTER est spĂ©cifiĂ©e, alors seules les lignes en entrĂ©e pour lesquelles filter_clause est vraie sont envoyĂ©es Ă  la fonction d'agrĂ©gat ; les autres lignes sont ignorĂ©es. Par exemple :

SELECT
    count(*) AS nonfiltres,
    count(*) FILTER (WHERE i < 5) AS filtres
FROM generate_series(1,10) AS s(i);
 nonfiltres | filtres
------------+---------
         10 |       4
(1 row)

Les fonctions d'agrĂ©gat prĂ©dĂ©finies sont dĂ©crites dans la Section 9.20. D'autres fonctions d'agrĂ©gat pourraient ĂȘtre ajoutĂ©es par l'utilisateur.

Une expression d'agrégat peut seulement apparaßtre dans la liste de résultats 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 calculés.

Lorsqu'une expression d'agrĂ©gat apparaĂźt dans une sous-requĂȘte (voir la Section 4.2.11 et la Section 9.22), l'agrĂ©gat est normalement Ă©valuĂ© sur les lignes de la sous-requĂȘte. Cependant, une exception survient si les arguments de l'agrĂ©gat (et clause_filtre si fourni) 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 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Ă©sultats ou dans la clause HAVING s'applique avec respect du niveau de requĂȘte auquel appartient l'agrĂ©gat.

4.2.8. Appels de fonction de fenĂȘtrage

Un appel de fonction de fenĂȘtrage 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 de fenĂȘtrage a accĂšs Ă  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 de fenĂȘtrage. La syntaxe d'un appel de fonction de fenĂȘtrage est une des suivantes :

nom_fonction ([expression [, expression ... ]]) [ FILTER ( WHERE clause_filtre ) ] OVER nom_window
nom_fonction ([expression [, expression ... ]]) [ FILTER ( WHERE clause_filtre ) ] OVER ( définition_window )
nom_fonction ( * ) [ FILTER ( WHERE clause_filtre ) ] OVER nom_window
nom_fonction ( * ) [ FILTER ( WHERE clause_filtre ) ] OVER ( définition_window )
    

oĂč dĂ©finition_fenĂȘtrage a comme syntaxe :

[ nom_fenĂȘtrage_existante ]
[ PARTITION BY expression [, ...] ]
[ ORDER BY expression [ ASC | DESC | USING opérateur ] [ NULLS { FIRST | LAST } ] [, ...] ]
[ clause_portée ]
    

et la clause clause_portĂ©e optionnelle fait partie de :

{ RANGE | ROWS | GROUPS } début_portée [ frame_exclusion ]
{ RANGE | ROWS | GROUPS } BETWEEN début_portée AND fin_portée [ frame_exclusion ]
    

avec début_portée et fin_portée pouvant faire partie de

UNBOUNDED PRECEDING
décalage PRECEDING
CURRENT ROW
décalage FOLLOWING
UNBOUNDED FOLLOWING
    

et frame_exclusion peut valoir

EXCLUDE CURRENT ROW
EXCLUDE GROUP
EXCLUDE TIES
EXCLUDE NO OTHERS
    

Ici, expression reprĂ©sente toute expression de valeur qui ne contient pas elle-mĂȘme d'appel Ă  des fonctions de fenĂȘtrage.

nom_fenĂȘtrage est une rĂ©fĂ©rence Ă  la spĂ©cification d'une fenĂȘtre nommĂ©e, dĂ©finie dans la clause WINDOW de la requĂȘte. Les spĂ©cifications de fenĂȘtres nommĂ©es sont habituellement rĂ©fĂ©rencĂ©es avec OVER nom_fenĂȘtrage, mais il est aussi possible d'Ă©crire un nom de fenĂȘtre entre parenthĂšses, puis de fournir en option une clause de tri et/ou une clause de portĂ©e (la fenĂȘtre rĂ©fĂ©rencĂ©e ne doit pas avoir ces clauses si elles sont fournies ici). Cette derniĂšre syntaxe suit les mĂȘmes rĂšgles que la modification d'un nom de fenĂȘtre existant dans une clause WINDOW ; voir la page de rĂ©fĂ©rence de SELECT pour les dĂ©tails.

La clause PARTITION BY groupe les lignes de la requĂȘte en partitions, qui sont traitĂ©es sĂ©parĂ©ment par la fonction de fenĂȘtrage. PARTITION BY fonctionne de la mĂȘme façon qu'une clause GROUP BY au niveau de la requĂȘte, sauf que ses expressions sont toujours des expressions et ne peuvent pas ĂȘtre des noms ou des numĂ©ros de colonnes en sortie. Sans PARTITION BY, toutes les lignes produites par la requĂȘte sont traitĂ©es comme une seule partition. La clause ORDER BY dĂ©termine l'ordre dans lequel les lignes d'une partition sont traitĂ©es par la fonction de fenĂȘtrage. Cela fonctionne de la mĂȘme façon que la clause ORDER BY d'une requĂȘte, mais ne peut pas non plus utiliser les noms ou les numĂ©ros des colonnes en sortie. Sans ORDER BY, les lignes sont traitĂ©es dans n'importe quel ordre.

La clause clause_portĂ©e indique l'ensemble de lignes constituant la portĂ©e de la fenĂȘtre, qui est un sous-ensemble de la partition en cours, pour les fonctions de fenĂȘtrage qui agissent sur ce sous-ensemble plutĂŽt que sur la partition entiĂšre. L'ensemble de lignes dans la portĂ©e peut varier suivant la ligne courante. Le sous-ensemble peut ĂȘtre spĂ©cifiĂ© avec le mode RANGE, avec le mode ROWS ou avec le mode GROUPS. Dans les deux cas, il s'exĂ©cute de dĂ©but_portĂ©e Ă  fin_portĂ©e. Si fin_portĂ©e est omis, la fin vaut par dĂ©faut CURRENT ROW.

Un dĂ©but_portĂ©e Ă  UNBOUNDED PRECEDING signifie que le sous-ensemble commence avec la premiĂšre ligne de la partition. De la mĂȘme façon, un fin_portĂ©e Ă  UNBOUNDED FOLLOWING signifie que le sous-ensemble se termine avec la derniĂšre ligne de la partition.

Dans les modes RANGE et GROUPS, un dĂ©but_portĂ©e Ă  CURRENT ROW signifie que le sous-ensemble commence avec la ligne suivant la ligne courante (une ligne que la clause ORDER BY de la fenĂȘtre considĂšre comme Ă©quivalente Ă  la ligne courante), alors qu'un fin_portĂ©e Ă  CURRENT ROW signifie que le sous-ensemble se termine avec la derniĂšre ligne homologue de la ligne en cours. Dans le mode ROWS, CURRENT ROW signifie simplement la ligne courante.

Dans les options de portĂ©e, offset de PRECEDING et offset de FOLLOWING, le offset doit ĂȘtre une expression ne contenant ni variables, ni fonctions d'agrĂ©gat, ni fonctions de fenĂȘtrage. La signification de offset dĂ©pend du mode de portĂ© :

  • Dans le mode ROWS, offset doit renvoyer un entier non nĂ©gatif non NULL, et l'option signifie que la portĂ©e commence ou finit au nombre spĂ©cifiĂ© de lignes avant ou aprĂšs la ligne courante.

  • Dans le mode GROUPS, offset doit de nouveau renvoyer un entier non nĂ©gatif non NULL, et l'option signifie que la portĂ©e commence ou finit au nombre spĂ©cifiĂ© de groupes de lignes Ă©quivalentes avant ou aprĂšs le groupe de la ligne courante, et oĂč un groupe de lignes Ă©quivalentes est un ensemble de lignes Ă©quivalentes dans le tri ORDER BY. (Il doit y avoir une clause ORDER BY dans la dĂ©finition de la fenĂȘtre pour utiliser le mode GROUPS.)

  • Dans le mode RANGE, ces options requiĂšrent que la clause ORDER BY spĂ©cifient exactement une colonne. offset indique la diffĂ©rence maximale entre la valeur de cette colonne dans la ligne courante et sa valeur dans les lignes prĂ©cĂ©dentes et suivantes de la portĂ©e. Le type de donnĂ©es de l'expression offset varie suivant le type de donnĂ©es de la colonne triĂ©e. Pour les colonnes ordonnĂ©es numĂ©riques, il s'agit habituellement du mĂȘme type que la colonne ordonnĂ©e. Mais pour les colonnes ordonnĂ©es de type date/heure, il s'agit d'un interval. Par exemple, si la colonne ordonnĂ©e est de type date ou timestamp, on pourrait Ă©crire RANGE BETWEEN '1 day' PRECEDING AND '10 days' FOLLOWING. offset est toujours requis pour ĂȘtre non NULL et non nĂ©gatif, bien que la signification de « non nĂ©gatif Â» dĂ©pend de son type de donnĂ©es.

Dans tous les cas, la distance jusqu'à la fin de la portée est limitée par la distance jusqu'à la fin de la partition, pour que les lignes proche de la fin de la partition, la portée puisse contenir moins de lignes qu'ailleurs.

Notez que dans les deux modes ROWS et GROUPS, 0 PRECEDING et 0 FOLLOWING sont Ă©quivalents Ă  CURRENT ROW. Le mode RANGE en fait aussi partie habituellement, pour une signification appropriĂ©e de « zĂ©ro Â» pour le type de donnĂ©es spĂ©cifique.

L'option frame_exclusion permet aux lignes autour de la ligne courante d'ĂȘtre exclues de la portĂ©e, mĂȘme si elles seraient incluses d'aprĂšs les options de dĂ©but et de fin de portĂ©e. EXCLUDE CURRENT ROW exclut la ligne courante de la portĂ©e. EXCLUDE GROUP exclut la ligne courante et ses Ă©quivalents dans l'ordre Ă  partir de la portĂ©e. EXCLUDE TIES exclut de la portĂ©e tout Ă©quivalent de la ligne courante mais pas la ligne elle-mĂȘme. EXCLUDE NO OTHERS spĂ©cifie explicitement le comportement par dĂ©faut lors de la non exclusion de la ligne courante ou de ses Ă©quivalents.

L'option par dĂ©faut est RANGE UNBOUNDED PRECEDING, ce qui est identique Ă  RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW. Avec ORDER BY, ceci configure le sous-ensemble pour contenir toutes les lignes de la partition Ă  partir de la ligne courante. Sans ORDER BY, toutes les lignes de la partition sont incluses dans le sous-ensemble de la fenĂȘtre, car toutes les lignes deviennent voisines de la ligne en cours.

Les restrictions sont que dĂ©but_portĂ©e ne peut pas valoir UNBOUNDED FOLLOWING, fin_portĂ©e ne peut pas valoir UNBOUNDED PRECEDING, et le choix de fin_portĂ©e ne peut pas apparaĂźtre avant la liste ci-dessus des options dĂ©but_portĂ©e et fin_portĂ©e que le choix de frame_start -- par exemple, RANGE BETWEEN CURRENT ROW AND valeur PRECEDING n'est pas autorisĂ©. Par exemple, ROWS BETWEEN 7 PRECEDING AND 8 PRECEDING est autorisĂ©, mĂȘme s'il ne sĂ©lectionnera aucune ligne.

Si FILTER est indiquĂ©, seules les lignes en entrĂ©e pour lesquelles clause_filtre est vrai sont envoyĂ©es Ă  la fonction de fenĂȘtrage. Les autres lignes sont simplement ignorĂ©es. Seules les fonctions de fenĂȘtrage qui sont des agrĂ©gats acceptent une clause FILTER.

Les fonctions de fenĂȘtrage internes sont dĂ©crites dans la Tableau 9.60. D'autres fonctions de fenĂȘtrage peuvent ĂȘtre ajoutĂ©es par l'utilisateur. De plus, toute fonction d'agrĂ©gat de type gĂ©nĂ©ral ou statistique peut ĂȘtre utilisĂ©e comme fonction de fenĂȘtrage. NĂ©anmoins, les agrĂ©gats d'ensemble triĂ© et d'ensemble hypothĂ©tique ne peuvent pas ĂȘtre utilisĂ©s actuellement comme des fonctions de fenĂȘtrage.

Les syntaxes utilisant * sont utilisĂ©es pour appeler des fonctions d'agrĂ©gats sans paramĂštres en tant que fonctions de fenĂȘtrage. Par exemple : count(*) OVER (PARTITION BY x ORDER BY y). Le symbole * n'est habituellement pas utilisĂ© pour les fonctions de fenĂȘtrage. Les fonctions de fenĂȘtrage n'autorisent pas l'utilisation de DISTINCT ou ORDER BY dans la liste des arguments de la fonction.

Les appels de fonctions de fenĂȘtrage 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 la Section 3.5, dans la Section 9.21 et dans la Section 7.2.5.

4.2.9. Conversions de type

Une conversion de type spĂ©cifie une conversion Ă  partir d'un type de donnĂ©es vers 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. Une conversion appliquĂ©e Ă  une chaĂźne constante reprĂ©sente l'affectation initiale d'un type pour une valeur constante, et donc cela rĂ©ussira pour tout type (si le contenu de la chaĂźne constante 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'exĂ©cution 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 incohĂ©rences et devrait probablement ĂȘtre Ă©vitĂ©e.

Note

La syntaxe par 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 par 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 la page de manuel de CREATE CAST.

4.2.10. Expressions de collationnement

La clause COLLATE surcharge le collationnement d'une expression. Elle est ajoutĂ©e Ă  l'expression Ă  laquelle elle s'applique :

expr COLLATE collationnement

oĂč collationnement est un identificateur pouvant ĂȘtre qualifiĂ© par son schĂ©ma. La clause COLLATE a prioritĂ© par rapport aux opĂ©rateurs ; des parenthĂšses peuvent ĂȘtre utilisĂ©es si nĂ©cessaire.

Si aucun collationnement n'est spécifiquement indiqué, le systÚme de bases de données déduit cette information du collationnement des colonnes impliquées dans l'expression. Si aucune colonne ne se trouve dans l'expression, il utilise le collationnement par défaut de la base de données.

Les deux utilisations principales de la clause COLLATE sont la surcharge de l'ordre de tri dans une clause ORDER BY, par exemple :

SELECT a, b, c FROM tbl WHERE ... ORDER BY a COLLATE "C";

et la surcharge du collationnement d'une fonction ou d'un opĂ©rateur qui produit un rĂ©sultat sensible Ă  la locale, par exemple :

SELECT * FROM tbl WHERE a > 'foo' COLLATE "C";
    

Notez que, dans le dernier cas, la clause COLLATE est attachĂ©e Ă  l'argument en entrĂ©e de l'opĂ©rateur. Peu importe l'argument de l'opĂ©rateur ou de la fonction qui a la clause COLLATE, parce que le collationnement appliquĂ© Ă  l'opĂ©rateur ou Ă  la fonction est dĂ©rivĂ© en considĂ©rant tous les arguments, et une clause COLLATE explicite surchargera les collationnements des autres arguments. (Attacher des clauses COLLATE diffĂ©rentes sur les arguments aboutit Ă  une erreur. Pour plus de dĂ©tails, voir la Section 23.2.) Du coup, ceci donne le mĂȘme rĂ©sultat que l'exemple prĂ©cĂ©dent :

SELECT * FROM tbl WHERE a COLLATE "C" > 'foo';

Mais ceci n'est pas valide :

SELECT * FROM tbl WHERE (a > 'foo') COLLATE "C";

car cette requĂȘte cherche Ă  appliquer un collationnement au rĂ©sultat de l'opĂ©rateur >, qui est du type boolean, type non sujet au collationnement.

4.2.11. 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 la Section 9.22 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.12. Constructeurs de tableaux

Un constructeur de tableau est une expression qui construit une valeur de tableau Ă  partir de la valeur 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). 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 la Section 4.2.9.

Les valeurs de tableaux multidimensionnels peuvent ĂȘtre construites 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%');
                                 array
-----------------------------------------------------------------------
 {2011,1954,1948,1952,1951,1244,1950,2005,1949,1953,2006,31,2412,2413}
(1 row)

SELECT ARRAY(SELECT ARRAY[i, i*2] FROM generate_series(1,5) AS a(i));
              array
----------------------------------
 {{1,2},{2,4},{3,6},{4,8},{5,10}}
(1 row)

La sous-requĂȘte doit renvoyer une seule colonne. Si la sortie de la sous- requĂȘte n'est pas de type tableau, 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. Si la colonne en sortie de la sous-requĂȘte est de type tableau, le rĂ©sultat sera un tableau du mĂȘme type, mais avec une dimension supplĂ©mentaire ; dans ce cas, toutes les lignes de la sous-requĂȘte doivent renvoyer des tableaux de dimension identique (dans le cas contraire, le rĂ©sultat ne serait pas rectangulaire).

Les indices d'un tableau construit avec ARRAY commencent toujours Ă  un. Pour plus d'informations sur les tableaux, voir la Section 8.15.

4.2.13. Constructeurs de lignes

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 une ou plus d'une expression (sĂ©parĂ©es par des virgules) pour les valeurs des champs de la ligne, et enfin 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 valeurligne.*, qui sera Ă©tendue en une liste d'Ă©lĂ©ments de la valeur ligne, ce qui est le comportement habituel de la syntaxe .* utilisĂ©e au niveau haut d'une liste SELECT (voir Section 8.16.5). Par exemple, si la table t a les colonnes f1 et f2, ces deux requĂȘtes sont identiques :

SELECT ROW(t.*, 42) FROM t;
SELECT ROW(t.f1, t.f2, 42) FROM t;
    

Note

Avant PostgreSQL 8.2, la syntaxe .* n'était pas étendue dans les constructeurs de lignes. De ce fait, ROW(t.*, 42) créait une ligne à deux champs dont le premier était une autre valeur de ligne. Le nouveau comportement est généralement 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 toute 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Ă©s Ă  une fonction qui accepte un paramĂštre composite. De plus, il est possible de comparer deux valeurs de lignes ou de 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.23. Les constructeurs de lignes peuvent aussi ĂȘtre utilisĂ©s en relation avec des sous-requĂȘtes, comme discutĂ© dans la Section 9.22.

4.2.14. 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 obligatoirement é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.17) peut ĂȘtre utilisĂ©e. Voici un exemple qui ne garantit pas qu'une division par zĂ©ro ne soit pas faite 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 à faire que si c'est nécessaire (dans cet exemple particulier, il serait sans doute mieux de contourner le problÚme en écrivant y > 1.5*x).

NĂ©anmoins, CASE n'est pas un remĂšde Ă  tout. Une limitation Ă  la technique illustrĂ©e ci-dessus est qu'elle n'empĂȘche pas l'Ă©valuation en avance des sous-expressions constantes. Comme dĂ©crit dans Section 37.7, les fonctions et les opĂ©rateurs marquĂ©s IMMUTABLE peuvent ĂȘtre Ă©valuĂ©s quand la requĂȘte est planifiĂ©e plutĂŽt que quand elle est exĂ©cutĂ©e. Donc, par exemple :

 SELECT CASE WHEN x > 0 THEN x ELSE 1/0 END FROM tab;
    

va produire comme rĂ©sultat un Ă©chec pour division par zĂ©ro, car le planificateur a essayĂ© de simplifier la sous-expression constante, mĂȘme si chaque ligne de la table a x > 0 de façon Ă  ce que la condition ELSE ne soit jamais exĂ©cutĂ©e.

Bien que cet exemple particulier puisse sembler stupide, il existe de nombreux cas moins Ă©vidents, n'impliquant pas de constantes, mais plutĂŽt des requĂȘtes exĂ©cutĂ©es par des fonctions, quand les valeurs des arguments des fonctions et de variables locales peuvent ĂȘtre insĂ©rĂ©es dans les requĂȘtes en tant que constantes toujours dans le but de la planification. À l'intĂ©rieur de fonctions PL/pgSQL, par exemple, utiliser une instruction IF-THEN- ELSE pour protĂ©ger un calcul risquĂ© est beaucoup plus sĂ»r qu'une expression CASE.

Une autre limitation de cette technique est qu'une expression CASE ne peut pas empĂȘcher l'Ă©valuation d'une expression d'agrĂ©gat contenue dans cette expression, car les expressions d'agrĂ©gat sont calculĂ©es avant les expressions « scalaires Â» dans une liste SELECT ou dans une clause HAVING. Par exemple, la requĂȘte suivante peut provoquer une erreur de division par zĂ©ro bien qu'elle semble protĂ©gĂ©e contre ce type d'erreurs :

SELECT CASE WHEN min(employees) > 0
            THEN avg(expenses / employees)
       END
    FROM departments;
    

Les agrĂ©gats min() et avg() sont calculĂ©s en mĂȘme temps avec toutes les lignes en entrĂ©e, donc si une ligne a une valeur 0 pour la colonne employees, l'erreur de division par zĂ©ro surviendra avant d'avoir pu tester le rĂ©sultat de min(). Il est prĂ©fĂ©rable d'utiliser une clause WHERE ou une clause FILTER pour empĂȘcher les lignes problĂ©matiques en entrĂ©e d'atteindre la fonction d'agrĂ©gat.