Fonctions fenêtre (Window Functions) MySQL

MySQLMySQLBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce laboratoire (lab), nous allons explorer le potentiel des fonctions fenêtres (window functions) MySQL. L'objectif est d'apprendre à effectuer des calculs sur des ensembles de lignes de table qui sont liées à la ligne actuelle.

Nous commencerons par attribuer des numéros de ligne uniques à chaque ligne en utilisant ROW_NUMBER(), en classant les employés par salaire. Ensuite, nous calculerons un total cumulatif en utilisant SUM OVER, utiliserons PARTITION BY pour des calculs groupés, et enfin, comparerons les lignes avec LAG. Ce lab fournit des exemples pratiques pour comprendre et appliquer efficacement ces fonctions fenêtres.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL mysql(("MySQL")) -.-> mysql/BasicKeywordsandStatementsGroup(["Basic Keywords and Statements"]) mysql/BasicKeywordsandStatementsGroup -.-> mysql/create_table("Table Creation") mysql/BasicKeywordsandStatementsGroup -.-> mysql/select("Data Retrieval") mysql/BasicKeywordsandStatementsGroup -.-> mysql/insert("Data Insertion") subgraph Lab Skills mysql/create_table -.-> lab-550921{{"Fonctions fenêtre (Window Functions) MySQL"}} mysql/select -.-> lab-550921{{"Fonctions fenêtre (Window Functions) MySQL"}} mysql/insert -.-> lab-550921{{"Fonctions fenêtre (Window Functions) MySQL"}} end

Attribuer des numéros de ligne avec ROW_NUMBER

Dans cette étape, nous allons explorer comment utiliser la fonction fenêtre (window function) ROW_NUMBER() dans MySQL pour attribuer un entier séquentiel unique à chaque ligne d'un ensemble de résultats. Cela est particulièrement utile lorsque vous avez besoin de classer ou de paginer des données.

Avant de plonger dans l'exemple pratique, comprenons la syntaxe de base de ROW_NUMBER() :

ROW_NUMBER() OVER (ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...)
  • ROW_NUMBER() : Il s'agit de la fonction fenêtre elle - même.
  • OVER() : Cette clause spécifie la fenêtre, qui est l'ensemble de lignes sur lequel la fonction opère.
  • ORDER BY : À l'intérieur de la clause OVER(), la clause ORDER BY détermine l'ordre dans lequel les numéros de ligne sont attribués. Vous pouvez spécifier une ou plusieurs colonnes pour le tri, et vous pouvez choisir l'ordre croissant (ASC) ou décroissant (DESC) pour chaque colonne.

Créons une table d'exemple nommée employees et insérons - y quelques données. Ouvrez votre terminal et connectez - vous à votre serveur MySQL en utilisant le client en ligne de commande mysql. Vous devrez peut - être fournir votre nom d'utilisateur et votre mot de passe.

mysql -u root -p

Une fois connecté, exécutez les instructions SQL suivantes pour créer la table employees et insérer des données :

CREATE TABLE employees (
    employee_id INT PRIMARY KEY,
    employee_name VARCHAR(50),
    department VARCHAR(50),
    salary DECIMAL(10, 2)
);

INSERT INTO employees (employee_id, employee_name, department, salary) VALUES
(1, 'Alice', 'Sales', 60000.00),
(2, 'Bob', 'Marketing', 55000.00),
(3, 'Charlie', 'Sales', 65000.00),
(4, 'David', 'IT', 70000.00),
(5, 'Eve', 'Marketing', 62000.00);

Maintenant, utilisons ROW_NUMBER() pour attribuer un numéro de ligne à chaque employé en fonction de leur salaire dans l'ordre décroissant. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) AS row_num
FROM
    employees;

Cette requête retournera le résultat suivant :

+-------------+---------------+------------+----------+---------+
| employee_id | employee_name | department | salary   | row_num |
+-------------+---------------+------------+----------+---------+
|           4 | David         | IT         | 70000.00 |       1 |
|           3 | Charlie       | Sales      | 65000.00 |       2 |
|           5 | Eve           | Marketing  | 62000.00 |       3 |
|           1 | Alice         | Sales      | 60000.00 |       4 |
|           2 | Bob           | Marketing  | 55000.00 |       5 |
+-------------+---------------+------------+----------+---------+
5 rows in set (0.00 sec)

Comme vous pouvez le voir, la colonne row_num contient le numéro de ligne attribué à chaque employé en fonction de leur salaire, le salaire le plus élevé recevant le numéro de ligne 1.

Vous pouvez également utiliser ROW_NUMBER() avec d'autres clauses ORDER BY. Par exemple, pour attribuer des numéros de ligne en fonction du nom de l'employé dans l'ordre croissant, vous pouvez utiliser la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    ROW_NUMBER() OVER (ORDER BY employee_name ASC) AS row_num
FROM
    employees;

Cela produira la sortie suivante :

+-------------+---------------+------------+----------+---------+
| employee_id | employee_name | department | salary   | row_num |
+-------------+---------------+------------+----------+---------+
|           1 | Alice         | Sales      | 60000.00 |       1 |
|           2 | Bob           | Marketing  | 55000.00 |       2 |
|           3 | Charlie       | Sales      | 65000.00 |       3 |
|           4 | David         | IT         | 70000.00 |       4 |
|           5 | Eve           | Marketing  | 62000.00 |       5 |
+-------------+---------------+------------+----------+---------+
5 rows in set (0.00 sec)

Cette fois, la colonne row_num reflète l'ordre alphabétique des noms des employés.

Calculer un total cumulatif avec SUM OVER

Dans cette étape, nous allons apprendre à calculer un total cumulatif en utilisant la fonction fenêtre (window function) SUM() OVER() dans MySQL. Un total cumulatif, également connu sous le nom de somme cumulative, est la somme d'une séquence de nombres qui est mise à jour chaque fois qu'un nouveau nombre est ajouté à la séquence. Cela est utile pour suivre l'évolution au fil du temps, calculer les ventes cumulées ou analyser les tendances.

La syntaxe de base de SUM() OVER() est la suivante :

SUM(expression) OVER (ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...)
  • SUM(expression) : Cela calcule la somme de l'expression spécifiée.
  • OVER() : Cette clause spécifie la fenêtre, qui est l'ensemble de lignes sur lequel la fonction opère.
  • ORDER BY : À l'intérieur de la clause OVER(), la clause ORDER BY détermine l'ordre dans lequel la somme est accumulée.

Nous continuerons à utiliser la table employees créée à l'étape précédente. Si vous ne l'avez pas créée, veuillez vous référer à l'étape précédente pour créer la table et insérer les données.

Maintenant, calculons le total cumulatif des salaires de tous les employés, triés par leur employee_id. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    SUM(salary) OVER (ORDER BY employee_id) AS running_total
FROM
    employees;

Cette requête produira le résultat suivant :

+-------------+---------------+------------+----------+---------------+
| employee_id | employee_name | department | salary   | running_total |
+-------------+---------------+------------+----------+---------------+
|           1 | Alice         | Sales      | 60000.00 |      60000.00 |
|           2 | Bob           | Marketing  | 55000.00 |     115000.00 |
|           3 | Charlie       | Sales      | 65000.00 |     180000.00 |
|           4 | David         | IT         | 70000.00 |     250000.00 |
|           5 | Eve           | Marketing  | 62000.00 |     312000.00 |
+-------------+---------------+------------+----------+---------------+
5 rows in set (0.00 sec)

La colonne running_total montre la somme cumulative des salaires au fur et à mesure que nous descendons les lignes, triées par employee_id. Par exemple, le total cumulatif pour Bob (employee_id 2) est la somme des salaires d'Alice et de Bob (60000 + 55000 = 115000).

Vous pouvez également trier le total cumulatif par d'autres colonnes, comme le salaire. Calculons le total cumulatif des salaires triés par salaire dans l'ordre croissant :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    SUM(salary) OVER (ORDER BY salary) AS running_total
FROM
    employees;

La sortie sera :

+-------------+---------------+------------+----------+---------------+
| employee_id | employee_name | department | salary   | running_total |
+-------------+---------------+------------+----------+---------------+
|           2 | Bob           | Marketing  | 55000.00 |      55000.00 |
|           1 | Alice         | Sales      | 60000.00 |     115000.00 |
|           5 | Eve           | Marketing  | 62000.00 |     177000.00 |
|           3 | Charlie       | Sales      | 65000.00 |     242000.00 |
|           4 | David         | IT         | 70000.00 |     312000.00 |
+-------------+---------------+------------+----------+---------------+
5 rows in set (0.00 sec)

Maintenant, le running_total est calculé en fonction de l'ordre croissant des salaires.

Utiliser PARTITION BY pour les calculs groupés

Dans cette étape, nous allons explorer comment utiliser la clause PARTITION BY dans les fonctions fenêtre (window functions) de MySQL pour effectuer des calculs sur des groupes de lignes. PARTITION BY divise les lignes en partitions, et la fonction fenêtre est appliquée à chaque partition indépendamment. Cela est utile pour calculer des agrégats au sein de groupes, classer des éléments au sein de catégories ou comparer des valeurs au sein de segments.

La syntaxe de base pour utiliser PARTITION BY avec une fonction fenêtre est la suivante :

function(expression) OVER (PARTITION BY column1, column2, ... ORDER BY column3 [ASC|DESC], ...)
  • function(expression) : Il s'agit de la fonction fenêtre que vous souhaitez utiliser (par exemple, SUM(), AVG(), ROW_NUMBER()).
  • OVER() : Cette clause spécifie la fenêtre.
  • PARTITION BY : Cette clause divise les lignes en partitions en fonction des colonnes spécifiées.
  • ORDER BY : Au sein de chaque partition, la clause ORDER BY détermine l'ordre dans lequel la fonction est appliquée.

Nous continuerons à utiliser la table employees créée dans les étapes précédentes. Si vous ne l'avez pas créée, veuillez vous référer aux étapes précédentes pour créer la table et insérer les données.

Calculons le salaire moyen pour chaque département en utilisant PARTITION BY. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    AVG(salary) OVER (PARTITION BY department) AS avg_salary_by_dept
FROM
    employees;

Cette requête produira le résultat suivant :

+-------------+---------------+------------+----------+----------------------+
| employee_id | employee_name | department | salary   | avg_salary_by_dept |
+-------------+---------------+------------+----------+----------------------+
|           4 | David         | IT         | 70000.00 |           70000.0000 |
|           2 | Bob           | Marketing  | 55000.00 |           58500.0000 |
|           5 | Eve           | Marketing  | 62000.00 |           58500.0000 |
|           1 | Alice         | Sales      | 60000.00 |           62500.0000 |
|           3 | Charlie       | Sales      | 65000.00 |           62500.0000 |
+-------------+---------------+------------+----------+----------------------+
5 rows in set (0.00 sec)

La colonne avg_salary_by_dept montre le salaire moyen pour le département de chaque employé. Notez que le salaire moyen est le même pour tous les employés du même département.

Maintenant, combinons PARTITION BY avec ROW_NUMBER() pour classer les employés au sein de chaque département en fonction de leur salaire. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank_by_salary
FROM
    employees;

Cette requête produira le résultat suivant :

+-------------+---------------+------------+----------+----------------+
| employee_id | employee_name | department | salary   | rank_by_salary |
+-------------+---------------+------------+----------+----------------+
|           4 | David         | IT         | 70000.00 |              1 |
|           5 | Eve           | Marketing  | 62000.00 |              1 |
|           2 | Bob           | Marketing  | 55000.00 |              2 |
|           3 | Charlie       | Sales      | 65000.00 |              1 |
|           1 | Alice         | Sales      | 60000.00 |              2 |
+-------------+---------------+------------+----------+----------------+
5 rows in set (0.00 sec)

La colonne rank_by_salary montre le classement de chaque employé au sein de leur département en fonction de leur salaire, le salaire le plus élevé recevant le classement 1. Le classement recommence pour chaque département en raison de la clause PARTITION BY department.

Comparer les lignes avec LAG

Dans cette étape, nous allons apprendre à utiliser la fonction fenêtre (window function) LAG() dans MySQL pour accéder aux données d'une ligne précédente dans le même ensemble de résultats. Cela est utile pour comparer les valeurs entre des lignes consécutives, calculer des différences ou identifier des tendances au fil du temps.

La syntaxe de base de LAG() est la suivante :

LAG(expression, offset, default_value) OVER (PARTITION BY column1, column2, ... ORDER BY column3 [ASC|DESC], ...)
  • LAG(expression, offset, default_value) : Cette fonction renvoie la valeur de l'expression d'une ligne située offset lignes avant la ligne actuelle.
    • expression : La colonne ou l'expression dont vous souhaitez récupérer la valeur de la ligne précédente.
    • offset : Le nombre de lignes à remonter. Si omis, la valeur par défaut est 1.
    • default_value : La valeur à renvoyer si l'offset dépasse le début de la partition. Si omis, la valeur par défaut est NULL.
  • OVER() : Cette clause spécifie la fenêtre.
  • PARTITION BY : Cette clause divise les lignes en partitions en fonction des colonnes spécifiées.
  • ORDER BY : Au sein de chaque partition, la clause ORDER BY détermine l'ordre dans lequel les lignes sont traitées.

Nous continuerons à utiliser la table employees créée dans les étapes précédentes. Si vous ne l'avez pas créée, veuillez vous référer aux étapes précédentes pour créer la table et insérer les données.

Comparons le salaire de chaque employé avec celui de l'employé précédent, triés par employee_id. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    LAG(salary, 1, 0) OVER (ORDER BY employee_id) AS previous_salary
FROM
    employees;

Cette requête produira le résultat suivant :

+-------------+---------------+------------+----------+-----------------+
| employee_id | employee_name | department | salary   | previous_salary |
+-------------+---------------+------------+----------+-----------------+
|           1 | Alice         | Sales      | 60000.00 |          0.00 |
|           2 | Bob           | Marketing  | 55000.00 |     60000.00 |
|           3 | Charlie       | Sales      | 65000.00 |     55000.00 |
|           4 | David         | IT         | 70000.00 |     65000.00 |
|           5 | Eve           | Marketing  | 62000.00 |     70000.00 |
+-------------+---------------+------------+----------+-----------------+
5 rows in set (0.00 sec)

La colonne previous_salary montre le salaire de l'employé précédent en fonction de employee_id. Pour Alice (employee_id 1), le previous_salary est 0 car il n'y a pas d'employé précédent. Nous avons spécifié 0 comme default_value dans la fonction LAG().

Maintenant, calculons la différence entre le salaire de chaque employé et celui de l'employé précédent. Exécutez la requête suivante :

SELECT
    employee_id,
    employee_name,
    department,
    salary,
    salary - LAG(salary, 1, 0) OVER (ORDER BY employee_id) AS salary_difference
FROM
    employees;

Cette requête produira le résultat suivant :

+-------------+---------------+------------+----------+-------------------+
| employee_id | employee_name | department | salary   | salary_difference |
+-------------+---------------+------------+----------+-------------------+
|           1 | Alice         | Sales      | 60000.00 |         60000.00 |
|           2 | Bob           | Marketing  | 55000.00 |         -5000.00 |
|           3 | Charlie       | Sales      | 65000.00 |         10000.00 |
|           4 | David         | IT         | 70000.00 |          5000.00 |
|           5 | Eve           | Marketing  | 62000.00 |         -8000.00 |
+-------------+---------------+------------+----------+-------------------+
5 rows in set (0.00 sec)

La colonne salary_difference montre la différence entre le salaire de chaque employé et celui de l'employé précédent.

Vous pouvez également utiliser PARTITION BY avec LAG(). Par exemple, si vous aviez une table avec des données de ventes pour différentes régions au fil du temps, vous pourriez utiliser PARTITION BY region pour comparer les ventes au sein de chaque région.

Résumé

Dans ce laboratoire (lab), nous avons exploré l'utilisation des fonctions fenêtre (window functions) de MySQL, en particulier l'attribution de numéros de ligne à l'aide de ROW_NUMBER(). Nous avons appris à utiliser la clause OVER() avec ORDER BY pour définir la fenêtre et déterminer l'ordre dans lequel les numéros de ligne sont attribués au sein d'un ensemble de résultats. Cela permet de classer les données et de les paginer.

Nous avons créé une table employees et l'avons remplie avec des données d'exemple. Ensuite, nous avons appliqué la fonction ROW_NUMBER() pour attribuer un entier séquentiel unique à chaque employé en fonction de leur salaire par ordre décroissant, ce qui illustre l'application pratique de cette fonction fenêtre.