rank, dense_rank

Les fonctions de ranking comme RANK et DENSE_RANK sont essentielles pour classer les lignes d’un jeu de résultats sur SQL Server. Elles permettent d’attribuer un rang à chaque ligne, en fonction d’un ordre défini. Dans cet article, nous allons explorer leur fonctionnement, illustré par des exemples concrets.

Introduction — définition, généralités, syntaxe

Sur SQL Server, la fonction RANK() permet d’attribuer un rang aux lignes d’un résultat, basé sur un ordre donné. Elle est souvent utilisée pour extraire un top-N, classer des performances ou segmenter des données.

Voici la syntaxe générale de RANK() :

RANK() OVER (PARTITION BY [colonne] ORDER BY [colonne])
  • PARTITION BY (optionnel) : permet de créer des groupes indépendants dans lesquels le classement s’effectue.
  • ORDER BY : détermine le critère de classement.

La fonction DENSE_RANK() est une autre fonction de ranking qui classe les lignes d’un jeu de résultats, tout comme RANK(). La différence majeure réside dans la manière dont elle gère les valeurs ex æquo : alors que RANK() laisse des « trous » dans la numérotation lorsque plusieurs lignes partagent le même rang, DENSE_RANK() attribue des rangs consécutifs sans sauter de numéro.
Cette particularité la rend utile lorsque l’on souhaite éviter des écarts dans le classement, par exemple pour établir un classement sportif, un palmarès ou toute situation où un classement compact est préférable.

Voici la syntaxe générale de DENSE_RANK() :

DENSE_RANK() OVER (PARTITION BY [colonne] ORDER BY [colonne])
  • PARTITION BY (optionnel) : permet de créer des groupes indépendants dans lesquels le classement est recalculé.
  • ORDER BY : définit le critère de classement.

Voyons quelques exemples concrets de l’utilisation de RANK et DENSE_RANK avec et sans partitions.

Exemples concrets de RANK et DENSE_RANK

Imaginons une table Ventes avec des vendeurs et leurs ventes totales.

CREATE TABLE Ventes (
    Vendeur NVARCHAR(50),
    ChiffreAffaires INT
);

INSERT INTO Ventes (Vendeur, ChiffreAffaires)
VALUES 
('Alice', 5000),
('Bob', 7000),
('Charlie', 7000),
('David', 4000),
('Eva', 3000);

Lançons la requête suivante

SELECT
    Vendeur,
    ChiffreAffaires,
    RANK() OVER (ORDER BY ChiffreAffaires DESC) AS Rang_RANK,
    DENSE_RANK() OVER (ORDER BY ChiffreAffaires DESC) AS Rang_DENSE_RANK
FROM
    Ventes;

Le résultat est

| Vendeur | ChiffreAffaires | Rang_RANK  | Rang_DENSE_RANK   |
| ------- | --------------- | ---------- | ----------------- |
| Bob     | 7000            | 1          | 1                 |
| Charlie | 7000            | 1          | 1                 |
| Alice   | 5000            | 3          | 2                 |
| David   | 4000            | 4          | 3                 |
| Eva     | 3000            | 5          | 4                 |

RANK() attribue le rang 1 à Bob et Charlie (car ils ont le même chiffre d’affaires). Le rang suivant est 3, car le rang 2 est « sauté » (1, 1, 3).

DENSE_RANK() attribue aussi le rang 1 à Bob et Charlie. Mais le rang suivant est 2, sans « trou » : 1, 1, 2.

RANK() saute des numéros en cas d’égalité. DENSE_RANK() compresse les rangs consécutifs.

Voyons maintenant ce que ça donne en utilisant la partition.

On reprend la table Ventes mais on ajoute une colonne Région pour grouper les vendeurs par région.

-- Nouvelle table avec région
CREATE TABLE Ventes (
    Vendeur NVARCHAR(50),
    Région NVARCHAR(50),
    ChiffreAffaires INT
);

INSERT INTO Ventes (Vendeur, Région, ChiffreAffaires)
VALUES 
('Alice', 'Nord', 5000),
('Bob', 'Nord', 7000),
('Charlie', 'Nord', 7000),
('David', 'Sud', 4000),
('Eva', 'Sud', 4000),
('Frank', 'Sud', 3000);

Lançons la requête suivante

SELECT
    Région,
    Vendeur,
    ChiffreAffaires,
    RANK() OVER (PARTITION BY Région ORDER BY ChiffreAffaires DESC) AS Rang_RANK,
    DENSE_RANK() OVER (PARTITION BY Région ORDER BY ChiffreAffaires DESC) AS Rang_DENSE_RANK
FROM
    Ventes;

On obtient

| Région | Vendeur | ChiffreAffaires | Rang_RANK  | Rang_DENSE_RANK   |
| ------ | ------- | --------------- | ---------- | ----------------- |
| Nord   | Bob     | 7000            | 1          | 1                 |
| Nord   | Charlie | 7000            | 1          | 1                 |
| Nord   | Alice   | 5000            | 3          | 2                 |
| Sud    | David   | 4000            | 1          | 1                 |
| Sud    | Eva     | 4000            | 1          | 1                 |
| Sud    | Frank   | 3000            | 3          | 2                 |

PARTITION BY Région relance le classement pour chaque région (Nord et Sud). Dans chaque partition, le ORDER BY définit le classement interne.

Dans le groupe Nord : Bob et Charlie sont ex aequo. RANK saute du 1 au 3, DENSE_RANK passe de 1 à 2.

Dans le groupe Sud : David et Eva sont ex aequo, même logique.

PARTITION BY est essentiel pour appliquer le ranking dans des sous-ensembles logiques (régions, catégories, périodes…). Sans lui, le classement est global.

Conclusion

Les fonctions de ranking comme RANK(), DENSE_RANK() sont des outils puissants pour organiser, analyser et présenter des résultats classés de façon précise dans SQL Server. Bien maîtriser leurs différences permet d’adapter chaque fonction à des besoins métiers variés : créer des top ventes, segmenter des clients, établir des podiums …

Auteur : Daniel MINKO FASSINOU

Laisser un commentaire




Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.