Question 1Lequel est requis quand tu écris une sous-requête (table dérivée) dans la clause FROM ?
Sous-requêtes ② — tables dérivées, sous-requêtes SELECT, CREATE / INSERT SELECT
Apprends les tables dérivées SQL, les sous-requêtes dans la clause SELECT, la combinaison avec CASE, et CREATE / INSERT SELECT — en pratique avec des données d'employés et de ventes dans ton navigateur.
Données utilisées dans cet article — employee / department / sales
La dernière fois, tu as utilisé une sous-requête dans WHERE.
Dans cet article, tu vas parcourir quatre applications dans l'ordre : mettre une sous-requête dans la clause `FROM` (une table dérivée), en écrire une dans une colonne `SELECT`, la combiner avec `CASE`, et construire une nouvelle table à partir du résultat d'une sous-requête.
Le matériel est constitué de trois tables de données d'employés.
En utilisant employee (30 employés), department (6 services) et sales (50 lignes de ventes), tu vas construire une table d'agrégation par service et aligner le total des ventes de chaque employé en colonne.
Tables dérivées dans FROM — traiter le résultat d'une sous-requête comme une seule table
Une table dérivée est une façon d'écrire une sous-requête dans la clause FROM afin que son résultat soit traité comme une seule table virtuelle.
Tu peux d'abord construire « le salaire moyen par service » comme une table d'agrégation, puis appliquer d'autres JOIN ou WHERE à cette table.
C'est pratique quand tu veux affiner un résultat agrégé d'un cran de plus.
La règle clé pour les tables dérivées est que tu dois lui donner un alias.
Écris AS alias comme dans FROM (SELECT ...) AS ds (SQLite permet aussi d'omettre AS) — sans cela, tu obtiens une erreur.
C'est par cet alias que tu références les colonnes de la table dérivée, comme ds.avg_salary.
-- Table dérivée dans FROM : agréger l'effectif et le salaire moyen par service, puis joindre avec department
SELECT d.dept_name, ds.headcount, ds.avg_salary
FROM (
SELECT dept_id, COUNT(*) AS headcount, AVG(salary) AS avg_salary
FROM employee
WHERE dept_id IS NOT NULL
GROUP BY dept_id
) AS ds
JOIN department d ON d.dept_id = ds.dept_id
ORDER BY ds.avg_salary DESC;
Sous-requêtes dans la clause SELECT — intégrer une valeur unique comme colonne
Quand tu écris une sous-requête scalaire dans la liste de colonnes SELECT, tu peux ajouter une colonne dont la valeur est calculée une par ligne.
Mets (SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id) dans une colonne, et tu peux aligner « le total des ventes de cet employé » comme une colonne par employé.
C'est une sous-requête corrélée qui référence le emp.emp_id externe.
-- Sous-requête dans la clause SELECT : ajouter le total des ventes de chaque employé comme une colonne
SELECT emp.name,
COALESCE(
(SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id),
0
) AS total_amount
FROM employee emp
ORDER BY emp.emp_id
LIMIT 6;
Un employé sans ventes fait renvoyer NULL à la sous-requête, donc le remplacer par 0 avec COALESCE(..., 0) rend la table plus lisible.
Une sous-requête dans la clause SELECT doit aussi tenir dans une ligne et une colonne.
Combiner avec CASE — attacher une étiquette de branchement selon la valeur d'une sous-requête
Une sous-requête dans la clause SELECT fonctionne tout aussi bien comme condition dans CASE.
Tu peux construire une colonne de rang du type « si le total des ventes est de 1 500 000 ou plus alors High, si supérieur à 0 alors Mid, sinon None » en jugeant la valeur de la sous-requête avec CASE WHEN.
Note que tu dois répéter la même sous-requête dans chaque WHEN de CASE (si la lisibilité prime, il y a aussi une façon de ne l'écrire qu'une fois avec WITH (expressions de table communes), que tu apprendras dans un chapitre ultérieur).
Dans cet article, tu vas couvrir la forme de base consistant à combiner directement une sous-requête et CASE.
-- Classer les employés selon leur nombre de ventes
SELECT emp.name,
(SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) AS sale_count,
CASE
WHEN (SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) >= 4 THEN 'Frequent'
WHEN (SELECT COUNT(*) FROM sales sale WHERE sale.emp_id = emp.emp_id) >= 1 THEN 'Occasional'
ELSE 'None'
END AS activity
FROM employee emp
ORDER BY sale_count DESC, emp.emp_id
LIMIT 8;
CREATE / INSERT SELECT — transformer le résultat d'une sous-requête en table
Écrire CREATE TABLE nouvelle_table AS SELECT ... te permet de sauvegarder le résultat du SELECT directement comme une nouvelle table (CTAS : Create Table As Select).
C'est souvent utilisé quand tu veux conserver un résultat agrégé sous forme d'instantané.
Quand tu veux ajouter des lignes à une table qui existe déjà, utilise INSERT INTO table_existante SELECT ... pour ajouter en masse le résultat du SELECT.
Ce sont des opérations d'écriture qui créent une table ou ajoutent des lignes.
Dans cet article, tu vas utiliser une table de travail jetable top_seller pour l'agrégation.
Pour obtenir le même résultat quel que soit le nombre d'exécutions, tu vas nettoyer la table de travail avec DROP TABLE IF EXISTS avant de la recréer.
L'INSERT en masse est plus rapide
INSERT INTO table SELECT ... insère les lignes cibles toutes d'un coup en une seule instruction.
Comparé à répéter INSERT INTO table VALUES (...) pour chaque ligne, l'analyse du SQL, les mises à jour d'index et la gestion de la transaction n'arrivent qu'une seule fois, donc plus tu insères de lignes, plus c'est rapide.
Quand tu copies ou déplaces une autre table ou un résultat agrégé, préfère l'INSERT ... SELECT en masse plutôt que de répéter INSERT ligne par ligne.
-- Sauvegarder un agrégat par service dans une table instantané
DROP TABLE IF EXISTS dept_summary;
CREATE TABLE dept_summary AS
SELECT dept_id, COUNT(*) AS headcount, AVG(salary) AS avg_salary
FROM employee
WHERE dept_id IS NOT NULL
GROUP BY dept_id;
SELECT * FROM dept_summary ORDER BY avg_salary DESC;
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Dans SELECT emp.name, (SELECT SUM(sale.amount) FROM sales sale WHERE sale.emp_id = emp.emp_id) AS total FROM employee emp, qu'arrive-t-il à la colonne total pour un employé sans aucune vente ?
Question 3Lequel décrit correctement CREATE TABLE top_seller AS SELECT ... ?