📌 Qu’est-ce qu’une fonction fenêtre ?#
Une fonction fenêtre :
- Travaille ligne par ligne,
- Peut accéder aux lignes voisines,
- Ne réduit pas le nombre de lignes (contrairement au
GROUP BY).
Elle repose sur la clause :
OVER (
PARTITION BY ...
ORDER BY ...
ROWS BETWEEN ...
)🧭 Navigation dans les lignes#
LAG(): valeur précédenteSELECT client_id, date_commande, LAG(date_commande) OVER ( PARTITION BY client_id ORDER BY date_commande ) AS prev_date FROM commandes;LEAD(): valeur suivanteSELECT client_id, date_commande, LEAD(date_commande) OVER ( PARTITION BY client_id ORDER BY date_commande ) AS next_date FROM commandes;FIRST_VALUE()/LAST_VALUE():SELECT client_id, montant, FIRST_VALUE(montant) OVER ( PARTITION BY client_id ORDER BY date_commande ) AS montant_initial FROM commandes;⚠️
LAST_VALUE()nécessite souvent unROWS BETWEEN UNBOUNDED FOLLOWINGselon les moteurs.
📊 Fonctions cumulées#
Exemple : cumul du montant des commandes
SELECT
client_id,
date_commande,
montant,
SUM(montant) OVER (
PARTITION BY client_id
ORDER BY date_commande
) AS cumul_client
FROM commandes;⚙️ Options de fenêtre#
| Option | Effet |
|---|---|
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW | Cumul depuis le début |
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING | Fenêtre glissante autour de chaque ligne |
PARTITION BY | Réinitialise le calcul par groupe |
ORDER BY | Définit la progression dans le groupe |
🧯 Pièges fréquents#
| ⚠️ Piège | ✅ Solution |
|---|---|
Oublier ORDER BY → résultats instables | Toujours ordonner les valeurs |
Mélanger GROUP BY avec OVER() | Comprendre que OVER ne réduit pas les lignes |
LAST_VALUE() renvoie la valeur courante | Ajouter ROWS BETWEEN UNBOUNDED FOLLOWING |
| Fenêtre trop large → résultats absurdes | Ajuster ROWS BETWEEN ... selon le besoin |
🏋️♂️ Entraînement#
- Obtenir la date précédente et suivante de chaque commande (LAG / LEAD).
- Calculer l’évolution du montant d’un client (montant courant vs précédent).
- Construire le montant cumulé par client.
- Calculer la différence entre deux jours successifs pour un produit.
duckdb.sql("""
SELECT
client_id, date_commande, montant,
LAG(montant) OVER (PARTITION BY client_id ORDER BY date_commande) AS prev,
SUM(montant) OVER (PARTITION BY client_id ORDER BY date_commande) AS cumul
FROM commandes
""").df()