SQL - Comment faire un classement avec RANK() ?

SQL - Comment faire un classement avec RANK() ?

Date de sortie
June 25, 2024
Auteur
Bertrand Fabre
“Je voudrai un classement avec le top 4 des ventes des produits pour chacun de mes sites sur 3 mois glissant tous les jours.”
“Oui bien sûr. Je planifie cela.”

😱 Je fais comment se classement des tops 4 ?!

Pas de panique, avec SQL et sur la plupart des bases de données (PostgreSQL, Redshift, BigQuery, Snowflake), il est possible de faire cela avec un fonction : RANK().

Cette fonction est une window function, j’en ferai un article de blog prochainement. Il faut surtout savoir que ce genre de fonctions ont une syntaxe spécifique, que nous allons voir ci-dessous.

Les données

Pour commencer, nous allons regarder ensemble à quoi ressemble les données.

WITH cte_sales AS (
    SELECT '001' AS site, 'produitA' AS product, 1000 AS turnover UNION ALL
    SELECT '001', 'produitB', 1500  UNION ALL
    SELECT '001', 'produitC', 1200  UNION ALL
    SELECT '002', 'produitA', 800   UNION ALL
    SELECT '002', 'produitB', 950   UNION ALL
    SELECT '002', 'produitC', 1100  UNION ALL
    SELECT '003', 'produitA', 1300  UNION ALL
    SELECT '003', 'produitB', 1200  UNION ALL
    SELECT '003', 'produitC', 900   UNION ALL
    SELECT '004', 'produitA', 1600  UNION ALL
    SELECT '004', 'produitB', 1400  UNION ALL
    SELECT '004', 'produitC', 1350
)
SELECT *
FROM cte_sales;

Ces données représentent le chiffre d’affaires généré par produit et par magasin. Les magasins sont donc représentés par le champ ‘site’, les produits par le champ ‘product’ et le chiffre d’affaires par le champ ‘turnover’. Pour ceux qui visualisent mieux les données dans la sortie BigQuery voici les résultats :

site
product
turnover
001
produitB
1500
001
produitC
1200
001
produitA
1000
002
produitC
1100
002
produitB
950
002
produitA
800
003
produitA
1300
003
produitB
1300
003
produitC
900
004
produitA
1600
004
produitB
1400
004
produitC
1350

La window function RANK()

Maintenant, ce que nous souhaitons faire c’est ajouter un champ qui représenterait le classement ou rang des meilleurs chiffres d’affaires de produits par site.

Dans notre cas, nous utilisons donc la fonction RANK().

En sortie, nous souhaitons avoir le numéro du site, le produit vendu, son chiffre d’affaires et le classement du CA de ce produit sur chaque site.

Nous allons donc ajouter ces champs dans le SELECT : site, product, turnover.

C’est à ce moment là que nous allons utiliser RANK().

On écrit donc d’abord la fonction RANK() le mot clé OVER puis la définition du fenêtrage voulu avec entre parenthèse PARTITION BY.

C’est lui qui va faire un découpage en groupe des données mais sans qu’on le voit. Il lui donne donc le champ site car on veut un classement par site.

Puis on veut faire un classement avec les meilleurs chiffre d’affaires en premier. On ajoute donc ORDER BY turnover DESC pour un classement décroissant.

On va lui donner le nom ‘rank’ qui me semble parlant.

Voici la requête SQL :

SELECT 
    site, 
    product, 
    turnover,
    RANK() OVER (PARTITION BY site ORDER BY turnover DESC) AS rank
FROM cte_sales;

J’exécute donc cette requête pour voir le résultat.

site
product
turnover
rank
001
produitB
1500
1
001
produitC
1200
2
001
ProduitA
1000
3
002
produitC
1100
1
002
produitB
950
2
002
produitA
800
3
003
produitA
1300
1
003
produitB
1300
1
003
produitC
900
3
004
produitA
1600
1
004
produitB
1400
2
004
produitC
1350
3

✅ La sortie est aussi classée selon les paramètres fournis dans la window function avec pour le 1er magasin, le produitB au 1er rang car c’est celui qui a réalisé le chiffre d’affaires le plus important du magasin.

☝️ Il y a une subtilité sur laquelle je souhaite que l’on s’arrête c’est le classement des produits pour le magasin ‘003’.

Il a 2 produits en 1ère position !

En effet, la fonction RANK() gère les ex-aequo.

La produit qui vient juste après ces ex-aequo prendra bien en compte qu’il y a 2 produits avant lui dans le classement et affichera donc la 3ème position.

Merci de votre lecture !