Plus facile à lire avec un fond crème, une teinte, plus de contraste ou un texte plus grand ? Choisissez vos couleurs et votre texte, une fois pour toutes les pages.

Leçon gratuite

PARTITION BY et cadres de fenêtre

Après cette leçon: Je peux classer les lignes à l'intérieur de chaque groupe et calculer une moyenne sur une fenêtre glissante.

Leçon de 60 minAucune commande

Classer dans chaque groupe et lisser une courbe

Avec partition by, une fonction de fenêtre recommence son calcul dans chaque groupe de lignes. Avec un cadre, elle ne regarde que quelques lignes voisines, comme les trois derniers jours.

Un directeur veut les deux meilleurs vendeurs de chaque magasin. Un restaurateur veut une courbe de recettes moins en dents de scie.

À la fin de cette leçon

Remarque

Je peux classer les lignes à l'intérieur de chaque groupe et calculer une moyenne sur une fenêtre glissante.

Mots clés

MotCe que ça veut direExemple
Partitionun groupe de lignes qui ont la même valeur
PARTITION BYdécoupe la fenêtre en partitions indépendantesover (partition by magasin)
Cadreles lignes voisines que la fenêtre regarde
ROWS BETWEENfixe le début et la fin du cadre, en nombre de lignes
Moyenne mobilela moyenne des dernières lignes, recalculée à chaque ligne
QUALIFYfiltre les lignes selon le résultat d'une fonction de fenêtre

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

PARTITION BY recommence le calcul par groupe

Sans partition by, la fenêtre est toute la table. Avec partition by magasin, chaque magasin a sa propre fenêtre.

Le rang repart de 1 dans chaque magasin. Chaque ligne reste dans le résultat : on ne regroupe rien.

À vous : un classement par magasin

Code: duckdb
-- Le classement des vendeurs recommence dans chaque magasin.
select nom, magasin, ventes,
  rank() over (partition by magasin order by ventes desc) as rang
from vendeurs
order by magasin, rang;
-- Retirez "partition by magasin" : le classement devient celui de toute la chaîne.

Filtrer le rang pour garder les premiers

On veut les deux meilleurs de chaque magasin. Le rang doit d'abord être calculé, puis filtré.

Placez le calcul dans une sous-requête, et filtrez dehors avec where rang <= 2. DuckDB propose aussi qualify, un filtre posé directement sur la fenêtre.

À vous : les deux meilleurs de chaque magasin

Code: duckdb
-- Les deux meilleurs vendeurs de chaque magasin.
select nom, magasin, ventes, rang
from (
  select nom, magasin, ventes,
    row_number() over (partition by magasin order by ventes desc) as rang
  from vendeurs
)
where rang <= 2
order by magasin, rang;
-- Changez 2 en 1 pour ne garder que le meilleur de chaque magasin.

À vous : le même filtre avec qualify

Code: duckdb
-- Le même résultat avec qualify, propre à DuckDB : un filtre sur la fenêtre.
select nom, magasin, ventes,
  row_number() over (partition by magasin order by ventes desc) as rang
from vendeurs
qualify rang <= 2
order by magasin, rang;
-- Quelle écriture trouvez-vous la plus facile à relire ?

Une erreur fréquente

Attention

Beaucoup pensent qu'on peut écrire where rang <= 2 dans la requête qui calcule le rang. DuckDB répond : « WHERE clause cannot contain window functions ». Le where agit avant la fenêtre. Utilisez une sous-requête ou qualify.

Un cadre limite la fenêtre aux lignes voisines

Avec order by, la fenêtre va du début jusqu'à la ligne courante. Un cadre la rétrécit.

rows between 2 preceding and current row veut dire : les deux lignes d'avant et la ligne courante. Pour une moyenne, cela donne une moyenne mobile sur trois jours.

Exemple : la moyenne mobile sur trois jours

JourMontantLignes du cadreCalculMoyenne
1er septembre1201120 / 1120,0
2 septembre1502(120 + 150) / 2135,0
3 septembre903(120 + 150 + 90) / 3120,0
4 septembre2003(150 + 90 + 200) / 3146,7
5 septembre1803(90 + 200 + 180) / 3156,7

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

À vous : la moyenne mobile

Code: duckdb
-- La moyenne des trois derniers jours, jour par jour.
select jour, montant,
  round(avg(montant) over (order by jour rows between 2 preceding and current row), 1) as moyenne_3j
from recettes
order by jour;
-- Changez 2 preceding en 1 preceding : la moyenne ne porte plus que sur deux jours.

Sans cadre, les ex aequo comptent ensemble

Quand over contient un order by et aucun cadre, DuckDB additionne du début jusqu'à la ligne courante et jusqu'à ses ex aequo.

Avec rows between unbounded preceding and current row, on compte les lignes une par une. Les deux écritures diffèrent seulement quand des valeurs sont égales.

Exemple : deux valeurs égales et deux cadres

LigneValeurCumul sans cadreCumul avec ROWS
a102010
b102020
c204040

Les cellules que les étudiants remplissent restent vides dans cet aperçu.

Une autre erreur fréquente

Attention

Beaucoup pensent que la moyenne mobile sur trois jours divise toujours par trois. Les deux premières lignes n'ont pas assez de voisines : le cadre est plus court, et la division aussi.

Vous enseignez à une classe ? Proposez ce module à vos étudiants avec un guide de l'enseignant, des devoirs corrigés et un laboratoire pour chaque étudiant.