Calculez rangs, cumuls et comparaisons intra-groupe sans écraser les lignes grâce à OVER et PARTITION BY.
Ouvrir cette leçon dans KodokonGROUP BY écrase les lignes en groupes ; une fonction de fenêtrage calcule un agrégat ou un rang en conservant chaque ligne. C'est l'outil des top N par groupe, des cumuls et des comparaisons à la moyenne de son équipe. Disponible dans SQLite depuis la version 3.25 (2018). Chargez le jeu de données.
CREATE TABLE employees (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
dept TEXT NOT NULL,
salary INTEGER NOT NULL
);
INSERT INTO employees (name, dept, salary)
VALUES
('alice', 'tech', 5200),
('bruno', 'tech', 4800),
('chloe', 'tech', 4800),
('david', 'tech', 4100),
('emma', 'sales', 3900),
('fanny', 'sales', 3600),
('gilles', 'sales', 3600),
('hugo', 'sales', 3200);Trois fonctions de rang, trois comportements face aux ex æquo : ROW_NUMBER numérote sans doublon (départage arbitraire), RANK donne le même rang aux ex æquo puis saute (1, 2, 2, 4), DENSE_RANK ne saute pas (1, 2, 2, 3). La clause WINDOW évite de répéter la définition de fenêtre (supportée par SQLite et PostgreSQL, pas par SQL Server).
SELECT name, salary,
ROW_NUMBER() OVER w AS row_num,
RANK() OVER w AS rnk,
DENSE_RANK() OVER w AS dense
FROM employees
WHERE dept = 'tech'
WINDOW w AS (ORDER BY salary DESC);PARTITION BY redémarre le calcul pour chaque sous-ensemble : une fenêtre par département, sans rien écraser. Combiné à une CTE, cela donne le pattern d'entretien d'embauche : les N mieux payés de chaque département. La CTE est obligatoire car une fonction de fenêtrage est évaluée après le WHERE : on ne peut pas filtrer sur rn directement.
WITH ranked AS (
SELECT name, dept, salary,
ROW_NUMBER() OVER (
PARTITION BY dept
ORDER BY salary DESC
) AS rn
FROM employees
)
SELECT name, dept, salary
FROM ranked
WHERE rn <= 2;Les agrégats classiques deviennent des fenêtres avec OVER : SUM(salary) OVER (ORDER BY ...) produit un cumul ligne à ligne. Précisez le cadre avec ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW pour un cumul strictement par ligne.
SELECT name, dept, salary,
SUM(salary) OVER (
PARTITION BY dept
ORDER BY salary DESC
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW
) AS running_total
FROM employees;