Une sous-requête est une requête SQL (Structured Query Language) imbriquée dans une autre requête SQL. La commande dans laquelle la sous-requête est imbriquée est appelée requête parent. Les sous-requêtes sont utilisées pour prétraiter les données utilisées dans la requête parent. Les sous-requêtes peuvent être appliquées dans SELECT
, INSERT
, UPDATE
, et DELETE
opérations.
Lorsque des sous-requêtes sont exécutées, la sous-requête est traitée en premier avant la requête parent. Lors de la création d'applications MySQL, l'utilisation de sous-requêtes offre plusieurs avantages :
- Ils décomposent les instructions SQL en unités logiques simples, ce qui peut faciliter leur compréhension et leur maintenance. En d'autres termes, les sous-requêtes aident à isoler les parties complexes des requêtes.
- Ils éliminent le besoin d'utiliser des
UNION
complexes déclarations etJOIN
déclarations. - Ils sont utilisés pour renforcer l'intégrité référentielle dans un scénario où les clés étrangères ne sont pas implémentées.
- Ils aident les développeurs à coder la logique métier dans les requêtes MySQL.
Dans ce guide, vous apprendrez :
- Comment utiliser une sous-requête corrélée
- Comment utiliser une sous-requête corrélée dans un opérateur de comparaison
- Comment utiliser une sous-requête en tant que table dérivée
Avant de commencer
Pour suivre ce guide, assurez-vous d'avoir les éléments suivants :
-
Si vous ne l'avez pas déjà fait, créez un compte Linode et une instance de calcul. Consultez nos guides Premiers pas avec Linode et Création d'une instance de calcul.
-
Suivez notre guide Configuration et sécurisation d'une instance de calcul pour mettre à jour votre système. Vous pouvez également définir le fuseau horaire, configurer votre nom d'hôte, créer un compte utilisateur limité et renforcer l'accès SSH.
-
Le logiciel serveur MySQL (ou MariaDB) installé sur votre Linode. Veuillez vous référer à la section MySQL, qui contient des guides décrivant comment installer MySQL sur plusieurs distributions Linux.
Configuration de la base de données
Pour comprendre le fonctionnement des sous-requêtes, créez d'abord un exemple de base de données. Cet exemple de base de données est utilisé pour exécuter les différents exemples de requêtes de ce guide :
-
SSH
à votre serveur et connectez-vous à MySQL en tant que root :mysql -u root -p
Lorsque vous y êtes invité, entrez le mot de passe root de votre serveur MySQL et appuyez sur Entrée continuer. Notez que le mot de passe root de votre serveur MySQL n'est pas le même que le mot de passe root de votre Linode.
Remarque
Si votre mot de passe n'est pas accepté, vous devrez peut-être exécuter la commande précédente avec
sudo
:sudo mysql -u root -p
-
Si votre mot de passe est accepté, vous devriez voir l'invite MySQL :
mysql >
Remarque
Si vous utilisez MariaDB, vous pouvez voir une invite comme celle-ci à la place :
MariaDB [(none)]>
-
Pour créer un exemple de base de données nommé
test_db
, exécutez :CREATE DATABASE test_db;
Vous devriez voir cette sortie, qui confirme que la base de données a été créée avec succès :
Query OK, 1 row affected (0.01 sec)
-
Basculer vers
test_db
base de données :USE test_db;
Vous devriez voir cette sortie :
Database changed
-
Vous avez créé le
test_db
et l'a sélectionné. Ensuite, créez une table nomméecustomers
:CREATE TABLE customers ( customer_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_name VARCHAR(50) ) ENGINE = InnoDB;
Vous devriez voir cette sortie :
Query OK, 0 rows affected (0.03 sec)
-
Ajouter des enregistrements aux
customers
table. Exécutez leINSERT
ci-dessous commandes une par une :INSERT INTO customers(customer_name) VALUES ('JOHN PAUL'); INSERT INTO customers(customer_name) VALUES ('PETER DOE'); INSERT INTO customers(customer_name) VALUES ('MARY DOE'); INSERT INTO customers(customer_name) VALUES ('CHRISTINE JAMES'); INSERT INTO customers(customer_name) VALUES ('MARK WELL'); INSERT INTO customers(customer_name) VALUES ('FRANK BRIAN');
Cette sortie s'affiche après l'insertion de chaque enregistrement :
Query OK, 1 row affected (0.00 sec) ...
-
Vérifiez que les informations des clients ont été insérées dans la base de données. Exécutez ce
SELECT
commande :SELECT * FROM customers;
Vous devriez voir cette liste de clients :
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 3 | MARY DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | | 6 | FRANK BRIAN | +-------------+-----------------+ 6 rows in set (0.00 sec)
-
Créer un
sales
table. Ce tableau utilise la colonnecustomer_id
pour référencer lescustomers
tableau :CREATE TABLE sales ( order_id BIGINT PRIMARY KEY AUTO_INCREMENT, customer_id BIGINT, sales_amount DECIMAL(17,2) ) ENGINE = InnoDB;
Cette sortie apparaît :
Query OK, 0 rows affected (0.03 sec)
-
Ensuite, remplissez le champ
sales
tableau avec quelques enregistrements. Exécutez leINSERT
ci-dessous commandes une par une :INSERT INTO sales (customer_id, sales_amount) VALUES ('1','25.75'); INSERT INTO sales (customer_id, sales_amount) VALUES ('2','85.25'); INSERT INTO sales (customer_id, sales_amount) VALUES ('5','3.25'); INSERT INTO sales (customer_id, sales_amount) VALUES ('4','200.75'); INSERT INTO sales (customer_id, sales_amount) VALUES ('5','88.10'); INSERT INTO sales (customer_id, sales_amount) VALUES ('1','100.00'); INSERT INTO sales (customer_id, sales_amount) VALUES ('2','45.00'); INSERT INTO sales (customer_id, sales_amount) VALUES ('4','15.80');
Cette sortie s'affiche après l'insertion de chaque enregistrement :
Query OK, 1 row affected (0.01 sec) ...
-
Vérifiez les données dans les
sales
table. Exécutez ceSELECT
commande :SELECT * FROM sales;
Cette liste de données de ventes devrait maintenant s'afficher :
+----------+-------------+--------------+ | order_id | customer_id | sales_amount | +----------+-------------+--------------+ | 1 | 1 | 25.75 | | 2 | 2 | 85.25 | | 3 | 5 | 3.25 | | 4 | 4 | 200.75 | | 5 | 5 | 88.10 | | 6 | 1 | 100.00 | | 7 | 2 | 45.00 | | 8 | 4 | 15.80 | +----------+-------------+--------------+ 8 rows in set (0.00 sec)
Après avoir configuré la base de données et les tables associées, vous pouvez maintenant implémenter les différentes sous-requêtes dans MySQL.
Comment utiliser une sous-requête corrélée
Une sous-requête corrélée est un type de requête imbriquée qui utilise les valeurs d'une requête parent. Ces types de requêtes font référence à la requête parent avec une colonne. La requête imbriquée est exécutée une fois pour chaque ligne de la requête parent.
L'exemple ci-dessous présente une requête qui sélectionne tous les clients. À l'intérieur de la requête, il y a une sous-requête corrélée qui récupère le montant total des ventes pour chaque client à partir des sales
tableau.
-
Exécutez l'exemple de requête :
SELECT customer_id, customer_name, (SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id) as total_sales_amount FROM customers;
Dans cet exemple, la sous-requête est
SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id
, qui apparaît entre parenthèses.Une liste des ventes totales réalisées par les clients s'affiche :
+-------------+-----------------+--------------------+ | customer_id | customer_name | total_sales_amount | +-------------+-----------------+--------------------+ | 1 | JOHN PAUL | 125.75 | | 2 | PETER DOE | 130.25 | | 3 | MARY DOE | NULL | | 4 | CHRISTINE JAMES | 216.55 | | 5 | MARK WELL | 91.35 | | 6 | FRANK BRIAN | NULL | +-------------+-----------------+--------------------+ 6 rows in set (0.00 sec)
La sortie ci-dessus de la sous-requête corrélée peut vous donner une liste résumée des commandes des clients. Veuillez noter que depuis
customer_id
s3
et6
n'ont aucun enregistrement associé dans la table des ventes, leurtotal_sales_amount
estNULL
. -
Une façon plus élégante de présenter cette liste est de renvoyer
0
au lieu deNULL
pour les clients avec zéro vente. Pour ce faire, entourez la sortie générée par la sous-requête d'unIFNULL(expression, 0)
déclaration. Exécutez cette commande mise à jour :SELECT customer_id, customer_name, IFNULL((SELECT SUM(sales_amount) FROM sales WHERE customer_id = customers.customer_id), 0) as total_sales_amount FROM customers;
La sortie suivante apparaît. MySQL renvoie 0,00 pour toutes les lignes qui auraient autrement renvoyé
NULL
valeurs.+-------------+-----------------+--------------------+ | customer_id | customer_name | total_sales_amount | +-------------+-----------------+--------------------+ | 1 | JOHN PAUL | 125.75 | | 2 | PETER DOE | 130.25 | | 3 | MARY DOE | 0.00 | | 4 | CHRISTINE JAMES | 216.55 | | 5 | MARK WELL | 91.35 | | 6 | FRANK BRIAN | 0.00 | +-------------+-----------------+--------------------+ 6 rows in set (0.00 sec)
Cette approche permet de s'assurer que la sortie ne nuit pas aux calculs ultérieurs sur les enregistrements.
Comment utiliser une sous-requête corrélée dans un opérateur de comparaison
Les sous-requêtes sont utiles pour déplacer la logique métier au niveau de la requête de la base de données. Les cas d'utilisation métier suivants présentent des sous-requêtes corrélées placées dans la clause WHERE d'une requête parent :
-
Considérez un scénario dans lequel vous souhaitez obtenir une liste de tous les clients enregistrés dans la base de données qui n'ont pas de ventes associées. Vous pouvez utiliser une sous-requête avec l'opérateur de comparaison MySQL
NOT IN
et récupérer ces clients :SELECT customer_id, customer_name FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
Dans cet exemple, la sous-requête est
SELECT customer_id FROM sales
, qui apparaît entre parenthèses. La commande SQL ci-dessus génère une liste de deux clients introuvables dans la table des ventes :+-------------+---------------+ | customer_id | customer_name | +-------------+---------------+ | 3 | MARY DOE | | 6 | FRANK BRIAN | +-------------+---------------+ 2 rows in set (0.00 sec)
Dans un environnement de production, vous pouvez utiliser ce type de jeu d'enregistrements pour prendre de meilleures décisions commerciales. Par exemple, vous pouvez créer un script utilisant un autre langage comme PHP ou Python pour envoyer un e-mail à ces clients et leur demander s'ils ont un problème pour passer une commande.
-
Un autre cas d'utilisation concerne le nettoyage des données. Par exemple, vous pouvez utiliser une sous-requête pour supprimer les clients qui n'ont jamais passé de commande :
DELETE FROM customers WHERE customer_id NOT IN (SELECT customer_id FROM sales);
La commande SQL ci-dessus supprime les deux clients et affiche ce qui suit :
Query OK, 2 rows affected (0.01 sec)
Si vous exécutez à nouveau une commande pour répertorier tous les clients, ces clients ne devraient plus apparaître dans le tableau :
SELECT * FROM customers;
La sortie ci-dessous confirme que les clients sans commandes associées ont été supprimés :
+-------------+-----------------+ | customer_id | customer_name | +-------------+-----------------+ | 1 | JOHN PAUL | | 2 | PETER DOE | | 4 | CHRISTINE JAMES | | 5 | MARK WELL | +-------------+-----------------+ 4 rows in set (0.00 sec)
Comment utiliser une sous-requête comme table dérivée
Lorsque des sous-requêtes sont utilisées dans le FROM
clause d'une requête parent, elles sont appelées tables dérivées . Ils sont très importants lors de la mise en œuvre de requêtes complexes qui nécessiteraient autrement une MySQL VIEW
, JOIN
, ou UNION
clause. Une table dérivée existe dans la requête qui l'a créée et n'est pas enregistrée de manière permanente dans la base de données.
Lorsque des sous-requêtes sont utilisées comme tables dérivées, elles isolent les différentes parties de l'instruction SQL. En d'autres termes, la sous-requête fournit une expression simplifiée d'une table qui peut être utilisée dans le cadre de la requête parent.
Remarque N'oubliez pas que chaque table dérivée doit avoir un alias.
Exécutez la commande ci-dessous pour créer une sous-requête de table dérivée dont l'alias est order_summary
:
SELECT customer_id
FROM
(
SELECT
customer_id,
count(order_id) as total_orders
FROM sales
group by customer_id
) as order_summary
WHERE order_summary.total_orders > 1;
RemarqueDans cette commande, la sous-requête apparaît entre parenthèses comme :
SELECT customer_id, count(order_id) as total_orders FROM sales group by customer_id
La commande ci-dessus interroge la table des ventes pour déterminer les clients avec plus d'une commande. Lorsque vous exécutez la requête, cette sortie apparaît :
+-------------+
| customer_id |
+-------------+
| 1 |
| 2 |
| 5 |
| 4 |
+-------------+
4 rows in set (0.00 sec)
La liste ci-dessus montre quatre customer_id
s qui ont plus d'une commande. Comme exemple de cas d'utilisation commerciale, vous pouvez utiliser une telle requête dans un script qui récompense les clients avec un bonus sur leur prochain achat.
Plus d'informations
Vous pouvez consulter les ressources suivantes pour plus d'informations sur ce sujet. Bien que ceux-ci soient fournis dans l'espoir qu'ils seront utiles, veuillez noter que nous ne pouvons pas garantir l'exactitude ou l'actualité des documents hébergés en externe.
- Sous-requêtes MySQL