Techniques avancées avec MySQL
Grouper les données
Parfois, vous pouvez avoir besoin de calculer une valeur pour un niveau de regroupement :
-
chiffre d’affaires cumulé par région,
-
salaire moyen par département.
Pour ce genre d’interrogation, vous allez pouvoir utiliser des fonctions d’agrégat (SUM, AVG, etc.) et regrouper les données grâce à la clause GROUP BY ; en complément, le résultat final, après regroupement, peut être restreint avec la clause HAVING.
Syntaxe
SELECT expression[,...] | *
FROM nom_table
[WHERE conditions]
GROUP BY expression [,...]
[HAVING conditions]
[ORDER BY expression [ASC | DESC][,...]]
[LIMIT [offset,] nombre_lignes]
La clause GROUP BY s’intercale entre les clauses WHERE et ORDER BY (si elles sont présentes). Elle spécifie les expressions utilisées pour effectuer le regroupement.
expression peut être :
-
une colonne,
-
une expression basée sur des colonnes,
-
un alias de colonne,
-
un numéro correspondant à la position d’une expression de la clause SELECT (syntaxe déconseillée et obsolète).
Dans les anciennes versions, le résultat de la requête était trié par défaut en ordre croissant sur les différentes expressions de la clause GROUP BY ; l’ordre du tri de chaque niveau de regroupement pouvait être défini explicitement avec des options ASC et DESC. Depuis la version 5.7, se baser sur le tri implicite provoqué par la clause GROUP BY était déprécié, et depuis la version 8.0.13, les options ASC et DESC de la clause GROUP BY ont été supprimées. Pour être certain d’avoir un ordre de tri bien précis, il est recommandé d’utiliser une clause ORDER BY explicite.
La plupart du temps, vous mettrez dans la clause GROUP...
Utiliser des sous-requêtes
1. Introduction
Une sous-requête est une requête SELECT qui est utilisée à l’intérieur d’une autre requête.
Une sous-requête peut être utilisée :
-
dans la clause WHERE d’une requête SELECT, UPDATE ou DELETE ;
-
dans la clause SELECT d’une requête SELECT ;
-
dans la clause FROM d’une requête SELECT ;
-
comme valeur affectée à une colonne dans une requête INSERT ou UPDATE ;
-
comme source de données d’une requête INSERT, à la place de la clause VALUES.
La sous-requête est toujours écrite entre parenthèses.
Elle peut contenir des jointures, ainsi que des clauses WHERE, GROUP BY, ORDER BY, etc. Une sous-requête peut aussi elle-même contenir des sous-requêtes !
Depuis la version 8, MySQL supporte les « expressions de table communes » (Common Table Expression - CTE), à savoir la possibilité de définir des sous-requêtes nommées dans une clause WITH qui précède la requête principale et de les utiliser dans cette dernière comme si c’étaient des tables.
2. Sous-requête scalaire
Une sous-requête qui retourne une seule colonne et au plus une seule ligne est appelée sous-requête scalaire.
Une telle sous-requête peut être utilisée partout où une valeur (un opérande) est attendu :
-
dans la clause WHERE d’une requête SELECT, INSERT, UPDATE ou DELETE ;
-
dans la clause SELECT d’une requête SELECT ;
-
comme valeur affectée à une colonne dans une requête INSERT ou UPDATE ;
-
comme opérande d’une fonction ou d’une expression.
Exemple
mysql> -- Ecart entre le prix de la collection 1 et le prix moyen ...
Utiliser les fonctions de fenêtrage
1. Introduction
Depuis la version 8, MySQL supporte les fonctions de fenêtrage (window functions), aussi parfois appelées fonctions analytiques.
Une fonction de fenêtrage est une fonction dont le résultat pour une ligne donnée est dérivé d’un ensemble de lignes relatif à cette ligne (une « fenêtre »). Ces fonctions permettent souvent de résoudre assez simplement des problèmes complexes qui auraient nécessité l’utilisation de plusieurs requêtes et des traitements dans une application cliente. Elles sont particulièrement utiles pour réaliser des rapports de type décisionnel.
Les fonctions analytiques permettent :
-
de réaliser des classements ;
-
d’effectuer des calculs sur des fenêtres glissantes (somme cumulative, moyenne glissante, etc.) ;
-
d’accéder à d’autres lignes que la ligne courante (ligne précédente ou suivante, première ou dernière ligne de la fenêtre, etc.).
Dans cette partie, nous présenterons les bases de l’utilisation des fonctions de fenêtrage en donnant quelques exemples représentatifs de leur intérêt. Pour avoir plus de détails, n’hésitez pas à vous reporter à la documentation (chapitre « 12.21 Window Functions » du manuel « MySQL 8.0 Reference Manual »).
La syntaxe générale d’une fonction analytique est la suivante :
fonction([paramètres]) OVER([partitionnement][tri][fenêtre])
La présence de la clause OVER indique l’utilisation d’une fonction de fenêtrage ; pour l’appel de cette dernière, les parenthèses sont obligatoires même s’il n’y a pas de paramètres....
Réunir le résultat de plusieurs requêtes
MySQL supporte l’utilisation de l’opérateur ensembliste UNION qui permet de réunir le résultat de plusieurs requêtes.
Syntaxe
requête_SELECT
UNION [ALL | DISTINCT]
requête_SELECT
[UNION ...]
[ORDER BY tri]
Les ordres SELECT doivent avoir le même nombre d’expressions et les expressions correspondantes doivent normalement avoir le même type (selon la documentation). Dans la pratique, si les expressions correspondantes ne sont pas du même type, il semble qu’elles sont converties en chaîne de caractères pour faire l’union.
Le titre des colonnes du résultat final est défini par la première requête.
Par défaut, toutes les lignes retournées sont distinctes ; le même résultat est obtenu en utilisant l’option DISTINCT. L’utilisation de l’option ALL permet de conserver toutes les lignes, même celles dupliquées.
Les ordres SELECT ne doivent pas contenir de clause ORDER BY ; ils peuvent par contre contenir des jointures, des sous-requêtes, ainsi que des clauses WHERE, GROUP BY, etc. Pour renforcer la lisibilité de la requête, les ordres SELECT peuvent être mis entre parenthèses.
Le résultat final de l’union peut être trié par une clause ORDER BY, avec la même syntaxe que pour un ordre SELECT simple (cf. chapitre Introduction à MySQL - Exécuter des requêtes SQL simples).
Exemples
mysql> SELECT titre FROM catalogue
-> UNION
-> SELECT IFNULL(CONCAT(titre,' - ',sous_titre),titre)
-> FROM livre WHERE id_collection = 1;
+-----------------------------------------------------------------------------------+ ...
Gérer les transactions et les accès concurrents
1. Définition
Dans la terminologie des bases de données relationnelles, une transaction est un ensemble d’ordres de mise à jour qui forme un tout indissociable du point de vue de la logique applicative. Les ordres de mise à jour d’une transaction ne peuvent être définitivement enregistrés dans la base de données que s’ils se sont tous exécutés sans erreur ; si un des ordres de mise à jour échoue, toutes les modifications déjà effectuées dans la transaction doivent être annulées. À la fin d’une transaction, la base de données est toujours dans un état cohérent du point de vue de la logique applicative.
À titre d’exemple, considérons une transaction de virement bancaire qui serait constituée de trois ordres de mise à jour :
-
un premier UPDATE pour débiter le premier compte ;
-
un deuxième UPDATE pour créditer le deuxième compte ;
-
un INSERT pour enregistrer l’opération dans un journal.
Si le deuxième UPDATE échoue pour une raison ou pour une autre, il faut annuler le premier UPDATE et ne pas effectuer l’ordre INSERT.
2. Gérer les transactions
Par défaut, MySQL fonctionne dans un mode validation automatique (option AUTOCOMMIT égale à 1) : chaque modification effectuée est immédiatement et définitivement enregistrée dans la base de données, ce qui ne permet pas de gérer correctement les transactions.
Par ailleurs, la gestion des transactions est supportée uniquement pour le type de table InnoDB.
À partir du moment où vous utilisez une table qui supporte les transactions, vous pouvez gérer les transactions à l’aide...
Effectuer des recherches à l’aide des expressions rationnelles
MySQL permet de faire des recherches à l’aide d’expressions rationnelles. Les expressions rationnelles permettent de spécifier des modèles complexes pour la recherche sur les chaînes.
MySQL propose plusieurs fonctions et opérateurs pour effectuer des opérations à l’aide d’une expression rationnelle.
REGEXP_LIKE REGEXP RLIKE |
Teste si une chaîne correspond à une expression rationnelle. |
REGEXP_INSTR |
Position d’une chaîne à l’intérieur d’une autre chaîne qui correspond à une expression rationnelle. |
REGEXP_SUBSTR |
Portion d’une chaîne qui correspond à une expression rationnelle. |
REGEXP_REPLACE |
Remplacement des occurrences d’une chaîne qui correspondent à une expression rationnelle par une autre chaîne. |
Les fonctions REGEXP_% sont apparues en version 8.0.4 ; avant cette version, seuls les opérateurs REGEXP et RLIKE (synonyme de REGEXP) étaient disponibles. À partir de la version 8.0.4, la gestion des expressions rationnelles a été réécrite en utilisant le standard International Components for Unicode (ICU) et les nouvelles fonctions ont été introduites. Pour des raisons de compatibilité ascendante, les opérateurs REGEXP et RLIKE existent toujours, mais ce sont dorénavant des alias de la fonction REGEXP_LIKE.
Syntaxe des fonctions
REGEXP_LIKE(expression,modèle[,mode])
expression [NOT] REGEXP modèle
expression [NOT] RLIKE modèle
REGEXP_INSTR(expression,modèle[,position[,occurrence[,option[,mode]]]])
REGEXP_SUBSTR(expression,modèle[,position[,occurrence[,mode]]])
REGEXP_REPLACE(expression,modèle,remplacement[,position[,occurrence
[,mode]]])
modèle est une expression rationnelle qui décrit...
Effectuer des recherches en texte intégral
1. Principes
MySQL permet d’effectuer des recherches de mots sur l’ensemble d’un texte (ou de plusieurs textes).
Pour utiliser cette fonctionnalité, il faut :
-
créer un index spécial, de type FULLTEXT ;
-
utiliser la fonction MATCH AGAINST dans les recherches.
Les index FULLTEXT peuvent être créés sur des colonnes de type CHAR, VARCHAR ou TEXT, mais uniquement sur des tables MyISAM ou InnoDB.
2. Création de l’index FULLTEXT
Les index FULLTEXT peuvent être créés lors de la création initiale de la table (dans l’ordre CREATE TABLE) ou ultérieurement (par un ordre ALTER TABLE ou un ordre CREATE FULLTEXT INDEX).
Pour créer un index FULLTEXT dans un ordre CREATE TABLE ou ALTER TABLE, il faut utiliser une clause FULLTEXT similaire à la clause INDEX présentée dans le chapitre Construire une base de données dans MySQL. L’ordre CREATE FULLTEXT INDEX est une variante de l’ordre CREATE INDEX présenté dans le chapitre Construire une base de données dans MySQL.
Syntaxe
CREATE TABLE nom_table
(
spécification_colonnes,
FULLTEXT(nom_colonne[,...])
)
ALTER TABLE nom_table ADD FULLTEXT(nom_colonne[,...])
CREATE FULLTEXT INDEX nom_index ON nom_table(nom_colonne[,...])
Exemple
mysql> CREATE FULLTEXT INDEX ix_texte
-> ON livre(titre,sous_titre,description);
Query OK, 0 rows affected , 1 warning (0.09 sec)
Records: 0 Duplicates: 0 Warnings: 1
mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------+ ...
Développer des programmes stockés
1. Introduction
Un programme stocké est un ensemble d’ordres SQL et d’instructions procédurales (structures de contrôle, déclaration de variables, etc.) qui réalise une tâche spécifique et qui est enregistré avec un nom dans la base de données. Le programme stocké peut ensuite être appelé à partir de différents environnements de développement pour exécuter la tâche en question.
Utiliser des programmes stockés offre plusieurs avantages :
-
Améliorer les performances : le code est stocké dans la base de données et il y a moins d’échange entre le client et le serveur.
-
Réutiliser du code : le code stocké peut être appelé par d’autres programmes qui n’ont pas besoin d’implémenter de nouveau la logique applicative.
-
Renforcer l’intégrité des données : les règles de gestion peuvent être codées à un seul endroit, dans les programmes stockés. Si les applications clientes n’ont pas le droit d’accéder directement aux tables mais doivent passer par les programmes stockés, l’intégrité des données est garantie.
Il existe deux types de programmes stockés :
-
les procédures ;
-
les fonctions.
2. Gestion des droits
Les privilèges suivants sont nécessaires pour gérer les programmes stockés :
-
CREATE ROUTINE pour créer un programme stocké ;
-
ALTER ROUTINE pour modifier ou supprimer un programme stocké (automatiquement attribué au créateur d’un programme stocké).
Par ailleurs, pour créer un programme stocké, il faut avoir les privilèges adaptés sur les objets (tables, vues...
Développer des triggers
1. Définition
Un trigger (déclencheur en français) est un programme stocké associé à une table et qui se déclenche automatiquement lorsqu’un événement de mise à jour (INSERT, UPDATE ou DELETE) survient sur la table. Un trigger n’est jamais explicitement exécuté par un autre programme.
Les triggers permettent d’implémenter des règles de gestion côté serveur. Les principales utilisations des triggers sont les suivantes :
-
Calculer automatiquement la valeur d’une colonne : par exemple, un trigger peut être utilisé pour calculer automatiquement un prix TTC à partir d’un prix HT et d’un taux de TVA.
-
Auditer les mises à jour effectuées dans la base de données : par exemple, à chaque fois qu’un article est supprimé, un trigger garde la trace de la suppression (qui, quand, quoi) dans une table d’audit.
2. Gestion des triggers
L’ordre SQL CREATE TRIGGER permet de créer un trigger.
Syntaxe :
CREATE TRIGGER [IF NOT EXISTS] [nom_base.]nom_trigger
{BEFORE | AFTER}
{INSERT | UPDATE | DELETE}
ON nom_table
FOR EACH ROW
[{FOLLOWS | PRECEDES} autre_trigger]
BEGIN
instructions;
END;
La clause IF NOT EXISTS empêche qu’une erreur se produise s’il existe déjà un trigger qui porte le même nom ; cette clause est apparue en version 8.0.29.
nom_base désigne la base de données dans laquelle le trigger doit être défini. Par défaut, le programme est stocké dans la base de données courante.
nom_trigger spécifie le nom du trigger. Ce nom doit respecter les règles de nommage...