Documentation PostgreSQL 9.3.25 > Tutoriel > FonctionnalitĂ©s avancĂ©es > Fonctions de fenĂȘtrage | |
![]() |
Héritage![]() |
Une fonction de fenĂȘtrage effectue un calcul sur un jeu d'enregistrements liĂ©s d'une certaine façon Ă l'enregistrement courant. On peut les rapprocher des calculs rĂ©alisables par une fonction d'agrĂ©gat mais, contrairement Ă une fonction d'agrĂ©gat, l'utilisation d'une fonction de fenĂȘtrage (de fenĂȘtrage) n'entraĂźne pas le regroupement des enregistrements traitĂ©s en un seul. Chaque enregistrement garde son identitĂ© propre. En coulisse, la fonction de fenĂȘtrage est capable d'accĂ©der Ă d'autres enregistrements que l'enregistrement courant du rĂ©sultat de la requĂȘte.
Voici un exemple permettant de comparer le salaire d'un employé avec le salaire moyen de sa division :
SELECT nomdep, noemp, salaire, avg(salaire) OVER (PARTITION BY nomdep) FROM salaireemp;
nomdep | noemp | salaire | avg -----------+-------+---------+----------------------- develop | 11 | 5200 | 5020.0000000000000000 develop | 7 | 4200 | 5020.0000000000000000 develop | 9 | 4500 | 5020.0000000000000000 develop | 8 | 6000 | 5020.0000000000000000 develop | 10 | 5200 | 5020.0000000000000000 personnel | 5 | 3500 | 3700.0000000000000000 personnel | 2 | 3900 | 3700.0000000000000000 ventes | 3 | 4800 | 4866.6666666666666667 ventes | 1 | 5000 | 4866.6666666666666667 ventes | 4 | 4800 | 4866.6666666666666667 (10 rows)
Les trois premiĂšres colonnes viennent directement de la table salaireemp, et il y a une ligne de sortie pour chaque ligne de la table. La quatriĂšme colonne reprĂ©sente une moyenne calculĂ©e sur tous les enregistrements de la table qui ont la mĂȘme valeur de nomdep que la ligne courante. (Il s'agit effectivement de la mĂȘme fonction que la fonction d'agrĂ©gat classique avg, mais la clause OVER entraĂźne son exĂ©cution en tant que fonction de fenĂȘtrage et son calcul sur le jeu appropriĂ© d'enregistrements.)
Un appel Ă une fonction de fenĂȘtrage contient toujours une clause OVER qui suit immĂ©diatement le nom et les arguments de la fonction. C'est ce qui permet de la distinguer syntaxiquement d'une fonction simple ou d'une fonction d'agrĂ©gat. La clause OVER dĂ©termine prĂ©cisĂ©ment comment les lignes de la requĂȘte sont Ă©clatĂ©es pour ĂȘtre traitĂ©es par la fonction de fenĂȘtrage. La liste PARTITION BY contenue dans la clause OVER spĂ©cifie la rĂ©partition des enregistrements en groupes, ou partitions, qui partagent les mĂȘmes valeurs pour la (les) expression(s) contenue(s) dans la clause PARTITION BY. Pour chaque enregistrement, la fonction de fenĂȘtrage est calculĂ©e sur les enregistrements qui se retrouvent dans la mĂȘme partition que l'enregistrement courant.
Vous pouvez aussi contrĂŽler l'ordre dans lequel les lignes sont traitĂ©es par les fonctions de fenĂȘtrage en utilisant la clause ORDER BY Ă l'intĂ©rieur de la clause OVER (la partition traitĂ©e par le ORDER BY n'a de plus pas besoin de correspondre Ă l'ordre dans lequel les lignes seront affichĂ©es). Voici un exemple :
SELECT nomdep, noemp, salaire, rank() OVER (PARTITION BY nomdep ORDER BY salaire DESC) FROM salaireemp;
nomdep | noemp | salaire| rank -----------+-------+--------+------ develop | 8 | 6000 | 1 develop | 10 | 5200 | 2 develop | 11 | 5200 | 2 develop | 9 | 4500 | 4 develop | 7 | 4200 | 5 personnel | 2 | 3900 | 1 personnel | 5 | 3500 | 2 ventes | 1 | 5000 | 1 ventes | 4 | 4800 | 2 ventes | 3 | 4800 | 2 (10 rows)
On remarque que la fonction rank produit un rang numĂ©rique dans la partition de l'enregistrement pour chaque valeur diffĂ©rente de l'ORDER BY, dans l'ordre dĂ©fini par la clause ORDER BY. rank n'a pas besoin de paramĂȘtre explicite, puisque son comportement est entiĂšrement dĂ©terminĂ© par la clause OVER.
Les lignes prises en compte par une fonction de fenĂȘtrage sont celles de la table virtuelle produite par la clause FROM de la requĂȘte filtrĂ©e par ses clauses WHERE, GROUP BY et HAVING, s'il y en a. Par exemple, une ligne rejetĂ©e parce qu'elle ne satisfait pas Ă la condition WHERE n'est vue par aucune fonction de fenĂȘtrage. Une requĂȘte peut contenir plusieurs de ces fonctions de fenĂȘtrage qui dĂ©coupent les donnĂ©es de façons diffĂ©rentes, par le biais de clauses OVER diffĂ©rentes, mais elles travaillent toutes sur le mĂȘme jeu d'enregistrements, dĂ©fini par cette table virtuelle.
ORDER BY peut ĂȘtre omis lorsque l'ordre des enregistrements est sans importance. Il est aussi possible d'omettre PARTITION BY, auquel cas il n'y a qu'une seule partition, contenant tous les enregistrements.
Il y a un autre concept important associĂ© aux fonctions de fenĂȘtrage : pour chaque enregistrement, il existe un jeu d'enregistrements dans sa partition appelĂ© son window frame (cadre de fenĂȘtre). Beaucoup de fonctions de fenĂȘtrage, mais pas toutes, travaillent uniquement sur les enregistrements du window frame, plutĂŽt que sur l'ensemble de la partition. Par dĂ©faut, si on a prĂ©cisĂ© une clause ORDER BY, la window frame contient tous les enregistrements du dĂ©but de la partition jusqu'Ă l'enregistrement courant, ainsi que tous les enregistrements suivants qui sont Ă©gaux Ă l'enregistrement courant au sens de la clause ORDER BY. Quand ORDER BY est omis, la window frame par dĂ©faut contient tous les enregistrements de la partition. [4] Voici un exemple utilisant sum :
SELECT salaire, sum(salaire) OVER () FROM salaireemp;
salaire| sum --------+------- 5200 | 47100 5000 | 47100 3500 | 47100 4800 | 47100 3900 | 47100 4200 | 47100 4500 | 47100 4800 | 47100 6000 | 47100 5200 | 47100 (10 rows)
Dans l'exemple ci-dessus, puisqu'il n'y a pas d'ORDER BY dans la clause OVER, la window frame est Ă©gale Ă la partition ; en d'autres termes, chaque somme est calculĂ©e sur toute la table, ce qui fait qu'on a le mĂȘme rĂ©sultat pour chaque ligne du rĂ©sultat. Mais si on ajoute une clause ORDER BY, on a un rĂ©sultat trĂšs diffĂ©rent :
SELECT salaire, sum(salaire) OVER (ORDER BY salaire) FROM salaireemp;
salaire| sum --------+------- 3500 | 3500 3900 | 7400 4200 | 11600 4500 | 16100 4800 | 25700 4800 | 25700 5000 | 30700 5200 | 41100 5200 | 41100 6000 | 47100 (10 rows)
Ici, sum est calculé à partir du premier salaire (c'est-à -dire le plus bas) jusqu'au salaire courant, en incluant tous les doublons du salaire courant (remarquez les valeurs pour les salaires identiques).
Les fonctions window ne sont autorisĂ©es que dans la liste SELECT et la clause ORDER BY de la requĂȘte. Elles sont interdites ailleurs, comme par exemple dans les clauses GROUP BY,HAVING et WHERE. La raison en est qu'elles sont exĂ©cutĂ©es aprĂšs le traitement de ces clauses. Par ailleurs, les fonctions de fenĂȘtrage s'exĂ©cutent aprĂšs les fonctions d'agrĂ©gat classiques. Cela signifie qu'il est permis d'inclure une fonction d'agrĂ©gat dans les arguments d'une fonction de fenĂȘtrage, mais pas l'inverse.
S'il y a besoin de filtrer ou de grouper les enregistrements aprĂšs le calcul des fonctions de fenĂȘtrage, une sous-requĂȘte peut ĂȘtre utilisĂ©e. Par exemple :
SELECT nomdep, noemp, salaire, date_embauche FROM (SELECT nomdep, noemp, salaire, date_embauche, rank() OVER (PARTITION BY nomdep ORDER BY salaire DESC, noemp) AS pos FROM salaireemp ) AS ss WHERE pos < 3;
La requĂȘte ci-dessus n'affiche que les enregistrements de la requĂȘte interne ayant un rang infĂ©rieur Ă 3.
Quand une requĂȘte met en jeu plusieurs fonctions de fenĂȘtrage, il est possible d'Ă©crire chacune avec une clause OVER diffĂ©rente, mais cela entraĂźne des duplications de code et augmente les risques d'erreurs si on souhaite le mĂȘme comportement pour plusieurs fonctions de fenĂȘtrage. Ă la place, chaque comportement de fenĂȘtrage peut ĂȘtre associĂ© Ă un nom dans une clause WINDOW et ensuite ĂȘtre rĂ©fĂ©rencĂ© dans OVER. Par exemple :
SELECT sum(salaire) OVER w, avg(salaire) OVER w FROM salaireemp WINDOW w AS (PARTITION BY nomdep ORDER BY salaire DESC);
Plus de dĂ©tails sur les fonctions de fenĂȘtrage sont disponibles dans la Section 4.2.8, « Appels de fonction de fenĂȘtrage », la Section 9.21, « Fonctions Window », la Section 7.2.4, « Traitement de fonctions Window » et la page de rĂ©fĂ©rence SELECT(7).
[4] Il existe des options pour dĂ©finir la window frame autrement, mais ce tutoriel ne les prĂ©sente pas. Voir la Section 4.2.8, « Appels de fonction de fenĂȘtrage » pour les dĂ©tails.