Questions d'entretien SQL, avec des réponses à exécuter
La plupart des entretiens SQL reprennent les mêmes idées. Voici les plus courantes, avec une réponse brève et une requête qui fonctionne dans PostgreSQL. Les exemples utilisent une petite base de boulangerie (customers, products, orders et order_items), pour que vous puissiez tester chacun d'eux dans une leçon de ce site.
Trouver la deuxième valeur la plus élevée
Une réponse simple consiste à trier par ordre décroissant et à sauter une ligne. Elle renvoie une seule ligne, même si plusieurs lignes partagent le deuxième prix.
Si les ex æquo comptent, classez avec DENSE_RANK et gardez le rang 2. DENSE_RANK ne saute aucun numéro après des ex æquo : le rang 2 est donc toujours la deuxième valeur distincte.
SELECT name, unit_price FROM ( SELECT name, unit_price, DENSE_RANK() OVER (ORDER BY unit_price DESC) AS r FROM products ) AS ranked WHERE r = 2;
Résultat : Chocolate cake slice, à 4.20.
Trouver les doublons
Groupez par la colonne qui devrait être unique et gardez les groupes qui contiennent plus d'une ligne.
SELECT order_date, COUNT(*) AS orders FROM orders GROUP BY order_date HAVING COUNT(*) > 1 ORDER BY order_date;
Résultat : Trois dates, chacune avec deux commandes : les 1er, 2 et 6 septembre.
Trouver les lignes sans correspondance
Utilisez un LEFT JOIN et gardez les lignes où le côté droit est NULL, ou utilisez NOT EXISTS. Les deux répondent à « quels clients n'ont jamais passé de commande ? ».
Évitez NOT IN avec une sous-requête qui peut renvoyer NULL : un seul NULL rend toute la condition indéterminée et vous n'obtenez aucune ligne.
SELECT c.first_name, c.last_name FROM customers AS c LEFT JOIN orders AS o ON o.customer_id = c.customer_id WHERE o.order_id IS NULL ORDER BY c.customer_id;
Résultat : Grace Kim et Hugo Meyer.
Premier élément de chaque groupe
Classez à l'intérieur de chaque groupe avec PARTITION BY, puis gardez le rang 1 dans une requête externe. Utilisez RANK pour conserver les ex æquo, ou ROW_NUMBER pour garder exactement une ligne par groupe.
SELECT category, name, units
FROM (
SELECT p.category, p.name, SUM(oi.quantity) AS units,
RANK() OVER (PARTITION BY p.category ORDER BY SUM(oi.quantity) DESC) AS rk
FROM products AS p
JOIN order_items AS oi ON oi.product_id = p.product_id
GROUP BY p.category, p.name
) AS ranked
WHERE rk = 1
ORDER BY category, name;Résultat : Le meilleur vendeur de chaque catégorie. Cake apparaît deux fois, car deux produits sont à égalité avec 3 unités.
Total cumulé
Utilisez SUM comme fonction de fenêtrage avec ORDER BY. Triez sur une colonne sans ex æquo, sinon les lignes à égalité sont additionnées ensemble.
SELECT order_id,
SUM(quantity) AS units,
SUM(SUM(quantity)) OVER (ORDER BY order_id) AS running_units
FROM order_items
GROUP BY order_id
ORDER BY order_id;Résultat : Unités par commande et total cumulé, qui termine à 56.
WHERE contre HAVING
WHERE filtre les lignes avant leur regroupement : il ne peut donc pas utiliser une fonction d'agrégation. HAVING filtre les groupes après l'agrégation. Dans l'exemple, WHERE retire d'abord les produits bon marché, et HAVING garde les catégories qui en comptent au moins deux parmi les produits restants.
SELECT category, COUNT(*) AS products FROM products WHERE unit_price > 2.50 GROUP BY category HAVING COUNT(*) >= 2 ORDER BY category;
Résultat : Bread et cake, avec deux produits chacun au-dessus de 2.50. Pastry et drinks n'ont qu'un seul produit au-dessus de 2.50 et sont exclues.
UNION contre UNION ALL
UNION supprime les lignes en double, ce qui demande un travail supplémentaire. UNION ALL garde tout et est plus rapide. Utilisez UNION ALL, sauf si vous avez besoin de supprimer les doublons.
SELECT city FROM customers UNION SELECT city FROM customers ORDER BY city;
Résultat : Cinq villes, chacune une seule fois. Avec UNION ALL, il y aurait 16 lignes.
Questions fréquentes
- Quelle est la différence entre DELETE, TRUNCATE et DROP ?
- DELETE supprime les lignes que vous choisissez (WHERE) et peut être annulé. TRUNCATE vide rapidement toute la table et conserve sa structure. DROP supprime la table elle-même, avec sa structure et ses données.
- Quelle est la différence entre INNER JOIN et LEFT JOIN ?
- INNER JOIN ne garde que les lignes qui correspondent des deux côtés. LEFT JOIN garde chaque ligne de la table de gauche et remplit le côté droit avec NULL lorsqu'aucune correspondance n'existe.
- Quelle est la différence entre RANK, DENSE_RANK et ROW_NUMBER ?
- Les trois numérotent les lignes d'un ordre. RANK donne le même numéro aux ex æquo et saute les numéros suivants. DENSE_RANK donne le même numéro aux ex æquo et ne saute rien. ROW_NUMBER ne répète jamais un numéro.
- Quel dialecte SQL utilisent ces réponses ?
- PostgreSQL. LIMIT/OFFSET, les fonctions de fenêtrage, les CTE et les jointures fonctionnent presque partout. Dans SQL Server, utilisez TOP ou OFFSET FETCH à la place de LIMIT, et dans Oracle, FETCH FIRST.