Data

10 requêtes SQL qui tombent en entretien (avec les corrigés)

Les 10 requêtes SQL classiques en entretien, avec les corrigés PostgreSQL, la notion utilisée et le piège à éviter pour chacune.

GratuitIntermédiaire9 min de lecture

Fiche récap

Coût
Gratuit
Niveau
Intermédiaire
Il te faut
  • PostgreSQL, pour tester les corrigés

Tu as compté ton score dans la vidéo ? Voici les 10 corrigés, en PostgreSQL, avec à chaque fois la notion utilisée, pourquoi ça marche, et le piège classique.

Moins de 7 ? Pas de panique : les 10 tiennent avec seulement 4 notions. Elles sont résumées en bas de la page.


Les tables d’exemple

Toutes les requêtes utilisent ces 5 tables. Copie-les dans ta base pour tester chaque corrigé toi-même.

CREATE TABLE users (
  id    SERIAL PRIMARY KEY,
  email TEXT NOT NULL
);

CREATE TABLE customers (
  id   SERIAL PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE orders (
  id          SERIAL PRIMARY KEY,
  customer_id INT REFERENCES customers(id),
  order_date  DATE NOT NULL,
  amount      NUMERIC(10,2) NOT NULL
);

CREATE TABLE employees (
  id            SERIAL PRIMARY KEY,
  name          TEXT NOT NULL,
  salary        NUMERIC(10,2) NOT NULL,
  department_id INT,
  manager_id    INT REFERENCES employees(id)
);

CREATE TABLE sales (
  id         SERIAL PRIMARY KEY,
  product_id INT NOT NULL,
  category   TEXT NOT NULL,
  qty        INT NOT NULL,
  amount     NUMERIC(10,2) NOT NULL,
  sale_date  DATE NOT NULL
);

1. Les emails en double

L’énoncé : trouve les emails présents plus d’une fois dans la table users.

La notion : GROUP BY + HAVING

SELECT email, COUNT(*) AS nb
FROM users
GROUP BY email
HAVING COUNT(*) > 1;

Pourquoi ça marche : GROUP BY regroupe les lignes par email, COUNT(*) les compte, et HAVING garde seulement les groupes de plus d’une ligne.

Le piège : mettre la condition dans un WHERE. WHERE filtre les lignes avant le regroupement, HAVING filtre les groupes après.


2. Les clients sans commande

L’énoncé : liste les clients qui n’ont jamais passé de commande.

La notion : LEFT JOIN

SELECT c.*
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
WHERE o.id IS NULL;

Pourquoi ça marche : le LEFT JOIN garde tous les clients, même sans commande. Pour ceux-là, les colonnes de orders valent NULL, et c’est ce qu’on filtre.

Le piège : utiliser un JOIN simple. Il ne garde que les clients qui ont au moins une commande, donc le résultat est toujours vide.


3. Les commandes par mois

L’énoncé : compte le nombre de commandes pour chaque mois.

La notion : GROUP BY sur une date

SELECT date_trunc('month', order_date)::date AS mois,
       COUNT(*) AS nb_commandes
FROM orders
GROUP BY mois
ORDER BY mois;

Pourquoi ça marche : date_trunc('month', ...) ramène chaque date au 1er du mois. Toutes les commandes d’un même mois tombent donc dans le même groupe.

Le piège : regrouper sur EXTRACT(MONTH ...) seul. Janvier 2025 et janvier 2026 se retrouvent alors mélangés.


4. Le 2e salaire le plus élevé

L’énoncé : trouve le deuxième salaire le plus élevé de l’entreprise.

La notion : sous-requête

SELECT MAX(salary) AS deuxieme_salaire
FROM employees
WHERE salary < (SELECT MAX(salary) FROM employees);

Pourquoi ça marche : la sous-requête trouve le salaire maximum. On cherche ensuite le plus grand salaire strictement en dessous.

Le piège : ORDER BY salary DESC LIMIT 1 OFFSET 1 sans DISTINCT. Si deux personnes ont le salaire maximum, tu renvoies le premier salaire au lieu du deuxième.

Variante acceptée en entretien :

SELECT DISTINCT salary
FROM employees
ORDER BY salary DESC
OFFSET 1 LIMIT 1;

5. Les départements au-dessus de la moyenne

L’énoncé : liste les départements dont le salaire moyen dépasse le salaire moyen de toute l’entreprise.

La notion : sous-requête dans un HAVING

SELECT department_id, ROUND(AVG(salary), 2) AS moyenne
FROM employees
GROUP BY department_id
HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);

Pourquoi ça marche : on calcule la moyenne de chaque département, puis on la compare à la moyenne globale, calculée par la sous-requête.

Le piège : comparer à la moyenne des moyennes des départements. Ce n’est pas la même chose si les départements n’ont pas le même nombre de personnes.


6. Les employés mieux payés que leur manager

L’énoncé : trouve les employés qui gagnent plus que leur manager.

La notion : jointure d’une table sur elle-même (self join)

SELECT e.name, e.salary, m.name AS manager, m.salary AS salaire_manager
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.salary > m.salary;

Pourquoi ça marche : on lit la table employees deux fois, une fois comme « employé » (e) et une fois comme « manager » (m), puis on relie chaque employé à son manager.

Le piège : oublier les alias. Sans e et m, impossible de savoir de quel salary on parle.


7. Supprimer les doublons

L’énoncé : supprime les emails en double dans users, en gardant la ligne la plus ancienne (le plus petit id).

La notion : DELETE avec jointure, ou fonction de fenêtre

DELETE FROM users a
USING users b
WHERE a.email = b.email
  AND a.id > b.id;

Pourquoi ça marche : pour chaque ligne, s’il existe une autre ligne avec le même email et un id plus petit, elle est supprimée. Seule la plus ancienne reste.

Le piège : lancer un DELETE sans tester. Écris d’abord la même condition dans un SELECT, ou travaille dans une transaction (BEGIN … ROLLBACK).

Variante avec une fonction de fenêtre :

DELETE FROM users
WHERE id IN (
  SELECT id FROM (
    SELECT id, ROW_NUMBER() OVER (PARTITION BY email ORDER BY id) AS rn
    FROM users
  ) t
  WHERE rn > 1
);

8. Le top 3 par catégorie

L’énoncé : pour chaque catégorie, trouve les 3 produits les plus vendus (en quantité).

La notion : fonction de fenêtre ROW_NUMBER

SELECT category, product_id, total
FROM (
  SELECT category, product_id, SUM(qty) AS total,
         ROW_NUMBER() OVER (PARTITION BY category ORDER BY SUM(qty) DESC) AS rang
  FROM sales
  GROUP BY category, product_id
) t
WHERE rang <= 3
ORDER BY category, total DESC;

Pourquoi ça marche : PARTITION BY category recommence le classement à 1 dans chaque catégorie. On garde ensuite les rangs 1 à 3.

Le piège : les ex æquo. ROW_NUMBER départage au hasard. Si l’entretien demande de garder les égalités, utilise RANK() ou DENSE_RANK().


9. Le chiffre d’affaires cumulé jour par jour

L’énoncé : affiche, pour chaque jour, le chiffre d’affaires du jour et le cumul depuis le début.

La notion : fonction de fenêtre SUM … OVER

SELECT sale_date,
       SUM(amount) AS ca_jour,
       SUM(SUM(amount)) OVER (ORDER BY sale_date) AS ca_cumule
FROM sales
GROUP BY sale_date
ORDER BY sale_date;

Pourquoi ça marche : SUM(amount) calcule le total de chaque jour. Le SUM(...) OVER (ORDER BY sale_date) additionne ensuite ces totaux, jour après jour.

Le piège : les jours sans vente n’apparaissent pas. Si on te demande une ligne pour chaque jour, il faut générer le calendrier avec generate_series.


10. La part de chaque catégorie en %

L’énoncé : pour chaque catégorie, affiche son chiffre d’affaires et sa part du total, en pourcentage.

La notion : fonction de fenêtre sur tout le résultat

SELECT category,
       SUM(amount) AS ca,
       ROUND(100.0 * SUM(amount) / SUM(SUM(amount)) OVER (), 1) AS pct
FROM sales
GROUP BY category;

Pourquoi ça marche : SUM(SUM(amount)) OVER (), avec des parenthèses vides, calcule le total de toutes les catégories sur chaque ligne. Il suffit de diviser.

Le piège : la division entière. 100 * 3 / 7 donne 42 en nombres entiers. Le 100.0 force un calcul décimal.


Les 4 notions qui débloquent tout

Notion Requêtes
GROUP BY (+ HAVING) 1, 3
Les jointures (LEFT JOIN, self join) 2, 6
Les sous-requêtes 4, 5, 7
Les fonctions de fenêtre (OVER, ROW_NUMBER) 8, 9, 10

Maîtrise ces 4 notions et tu sais écrire les 10.


Pour t’entraîner

  • SQLBolt : des exercices courts et interactifs, directement dans le navigateur, pour revoir les bases.
  • SQL Murder Mystery : une enquête policière à résoudre uniquement en SQL.
  • PostgreSQL Exercises (pgexercises) : des exercices sur PostgreSQL, des bases jusqu’aux fonctions de fenêtre.

Bonne chance pour ton entretien, futur codeur 🚀

Publié le

Guides & ressources

Testé sur ma machine

Des guides pas à pas et des sélections de sites pour progresser en dev, IA, data ou cyber. Gratuit, sans inscription.

La newsletter du lundi

L’actu tech en 5 minutes

Chaque lundi, les sujets IA, tech et dev de la semaine expliqués simplement, plus mes nouveaux guides. Zéro spam.

En vidéo

Un outil par vidéo

Chaque semaine, un outil, une astuce ou une ressource, avec le guide à récupérer en commentaire.

L’actu tech en 5 minutes, chaque lundi

Les sujets IA, tech et dev de la semaine expliqués simplement, plus mes nouveaux guides. Gratuit, désinscription en un clic.