Question 1Laquelle des propositions suivantes décrit correctement un CTE dans WITH nom AS (SELECT ...) SELECT ... FROM nom; ?
Clause WITH — étager ta requête avec des résultats intermédiaires nommés
Cet article fait partie du Cours de SQL, qui vous permet de maîtriser à partir de zéro des compétences SQL concrètes, des bases jusqu'aux requêtes complexes et à l'optimisation SQL.
Apprends la clause SQL WITH (CTE) : construis un CTE high_earner, JOIN avec department, puis enchaîne dept_avg → top_earner pour un agrégat multi-étapes sur des données employé.
Données utilisées dans cet article — employee et department
Un CTE (Common Table Expression) est un mécanisme où tu écris WITH nom AS (SELECT ...) pour donner un nom à une sous-requête, puis tu références ce nom dans les requêtes qui suivent.
Comme tu peux découper une sous-requête profondément imbriquée en étapes, ton code devient bien plus lisible.
Le matériel est la table employee (30 lignes ; la colonne manager_id pointe vers l'emp_id du manager, une structure auto-référencée) et la table department (6 lignes).
Tu vas faire des exercices qui utilisent des CTE pour écrire des agrégats multi-étapes de façon plus lisible.
Construire un résultat intermédiaire nommé avec WITH — rendre les requêtes multi-étapes lisibles
Quand tu écris WITH nom AS (SELECT ...), le résultat du SELECT interne reçoit un nom, et tu peux le référencer depuis FROM ou JOIN dans la requête principale qui suit.
Au lieu d'écrire le processus en deux étapes « d'abord construire un résultat intermédiaire, puis l'utiliser pour produire le résultat final » sous forme de sous-requête imbriquée, tu peux le décomposer dans une forme qui se lit de haut en bas.
Un CTE est un nom temporaire qui disparaît une fois la requête principale terminée — il ne crée pas de vraie table.
La syntaxe est WITH nom AS ( ... ) SELECT ... FROM nom ...;.
-- Regrouper les hauts salaires dans le CTE high_earner,
-- puis joindre avec department pour attacher le nom du service
WITH high_earner AS (
SELECT emp_id, name, dept_id, salary
FROM employee
WHERE salary >= 7000000
)
SELECT h.name, h.salary, d.dept_name
FROM high_earner h
LEFT JOIN department d ON h.dept_id = d.dept_id
ORDER BY h.salary DESC;
Dans le code ci-dessus, le nom high_earner découpe le résultat intermédiaire « les employés dont salary >= 7 000 000 », et la requête principale le référence comme une table avec FROM high_earner.
Voici à quoi ressemble ce flux sous forme de schéma.
Tu peux écrire le même traitement avec une sous-requête (un SELECT imbriqué dans les parenthèses d'un autre SELECT).
Reconstruisons la version WITH précédente sous forme de sous-requête au lieu d'un CTE.
-- Le même traitement écrit comme sous-requête (table dérivée)
-- Un SELECT vit dans les parenthèses du FROM, donc tu lis externe → interne → externe
SELECT h.name, h.salary, d.dept_name
FROM (
SELECT emp_id, name, dept_id, salary
FROM employee
WHERE salary >= 7000000
) AS h
LEFT JOIN department d ON h.dept_id = d.dept_id
ORDER BY h.salary DESC;
Le résultat est exactement le même qu'avec la version WITH, mais avec la version sous-requête tu dois plonger dans un SELECT imbriqué à l'intérieur de FROM pour comprendre ce que fait le SELECT interne.
La version WITH découpe le résultat intermédiaire avec le nom `high_earner`, donc les deux étapes « ① filtrer les hauts salaires → ② attacher le nom du service » se lisent directement de haut en bas.
L'écart grandit à mesure que tu ajoutes des étapes intermédiaires — quand tu en as 3 ou 4, les sous-requêtes profondément imbriquées deviennent difficiles à suivre.
Chaîner plusieurs clauses WITH — découper un agrégat multi-étapes une étape à la fois
Après WITH, tu peux lister plusieurs CTE séparés par des virgules.
La forme est WITH a AS (...), b AS (...) SELECT ..., et un CTE plus tardif peut référencer un précédent.
Cela te permet de découper un agrégat multi-étapes (« calculer la moyenne par service » → « sélectionner les employés au-dessus de cette moyenne » → « attacher le nom du service ») en étapes nommées une à la fois, pour que même dans une longue requête, le rôle de chaque étape reste séparé.
-- ① dept_avg : salaire moyen par service
-- ② top_earner : employés au-dessus de la moyenne de leur propre service
-- ③ Requête principale : attacher le nom du service et sortir
WITH dept_avg AS (
SELECT dept_id, AVG(salary) AS avg_salary
FROM employee
WHERE dept_id IS NOT NULL
GROUP BY dept_id
),
top_earner AS (
SELECT e.name, e.dept_id, e.salary
FROM employee e
JOIN dept_avg da ON e.dept_id = da.dept_id
WHERE e.salary > da.avg_salary
)
SELECT d.dept_name, t.name, t.salary
FROM top_earner t
JOIN department d ON t.dept_id = d.dept_id
ORDER BY d.dept_name, t.salary DESC;
Vérification des connaissances
Répondez à chaque question une par une.
Question 2Comparé à SELECT h.name FROM (SELECT name FROM employee WHERE salary >= 7000000) AS h JOIN department d ON h.dept_id = d.dept_id;, quelle est la différence quand tu réécris le même traitement avec un CTE WITH ?
Question 3Laquelle des propositions suivantes décrit correctement le fait de lister plusieurs CTE comme WITH a AS (...), b AS (...) SELECT ... FROM b; ?