La majorité des candidats échouent sur six concepts SQL cruciaux en entretien data, comme les fonctions fenêtrées ou la gestion des NULLs. Maîtriser ces notions avec exemples concrets vous démarquera clairement, car leur difficulté vient souvent d’une compréhension superficielle ou de mauvaises pratiques.
3 principaux points à retenir.
- Les fonctions fenêtrées demandent un ordre précis, sans quoi les résultats sont aléatoires.
- Différence HAVING vs WHERE : seules les conditions après agrégats vont en HAVING.
- Gestion des NULLs oblige à utiliser COALESCE et IS NULL pour éviter erreurs et omissions.
Pourquoi les fonctions fenêtrées déconcertent-elles les candidats
Les fonctions fenêtrées ont le don de créer des sueurs froides chez certains candidats lors des entretiens data. Mais pourquoi ? Un des principaux coupables, c’est la clause ORDER BY. Beaucoup de professionnels sous-estiment son importance. Alors, plongeons dans le cœur du problème.
Commençons par les fonctions comme LAG() et LEAD(). Ces fonctions sont conçues pour accéder aux lignes précédentes ou suivantes à l’intérieur d’une partition de données. Pour qu’elles fonctionnent correctement, il est impératif d’utiliser ORDER BY à l’intérieur de la définition de la fenêtre. Imaginez un chef d’orchestre ; sans lui, l’harmonie s’effondre. Si vous omettez ORDER BY, vous vous exposez à des résultats erronés et non déterministes. En clair, chaque exécution peut aboutir à quelque chose de différent. Ceci est particulièrement vrai dans PostgreSQL, où la gestion des fenêtres est cruciale pour obtenir des résultats cohérents.
Parlons des erreurs communes que les candidats commettent. Prenons un exemple simple :
SELECT
sales,
LAG(sales) OVER (PARTITION BY region) AS previous_sales
FROM
sales_data;
Quelle est la problématique ici ? Sans ORDER BY, la fonction LAG() ne saura pas comment se positionner dans l’ordre des lignes. Conséquence : des données aléatoires ! L’ajout de ORDER BY permet de définir le cadre, indiquant comment les lignes doivent être abordées :
SELECT
sales,
LAG(sales) OVER (PARTITION BY region ORDER BY sale_date) AS previous_sales
FROM
sales_data;
En ajoutant ORDER BY, vous créez un véritable chemin pour la fonction, lui permettant d’accéder correctement aux lignes désirées. Le concept de partition et d’ordre devient alors limpide. Pour synthétiser, voici un tableau des erreurs fréquentes par rapport aux bonnes pratiques :
| Erreurs Commune | Bonnes Pratiques |
|---|---|
| Oublier ORDER BY dans une fonction fenêtrée | Toujours inclure ORDER BY pour définir le cadre |
| Utiliser des fonctions fenêtrées sans partitionnement | Utiliser PARTITION BY pour structurer les données |
| Ne pas tester le résultat | Valider les résultats avec des cas de test. |
En répétant ces bonnes pratiques, vous aurez toutes les clés en main pour briller lors de vos entretiens et éviter d’être paralysé par ces fonctions apparemment simples ! Pour plus de conseils, jetez un œil à cet article.
Comment distinguer HAVING et WHERE sans erreur
Dans le royaume des requêtes SQL, il existe deux personnages souvent confondus : WHERE et HAVING. Pourtant, leur rôle respectif est crucial et, surtout, très différent. Pour faire simple, WHERE agit avant les agrégations, tandis que HAVING fait son effet après. Cette distinction, bien que logique, est souvent mal saisie par les candidats en entretien, et cela peut mener à un vrai fiasco lors de l’usage des agrégats.
Pour comprendre cela, il faut s’intéresser à l’ordre d’exécution des clauses SQL. Quand vous exécutez une requête, voici ce qui se passe : d’abord, FROM est évalué pour déterminer les tables à interroger. Ensuite, WHERE filtre les lignes en fonction des conditions, avant que n’interviennent les agrégations via GROUP BY. C’est à ce stade que les données sont regroupées, et enfin, l’étape d’évaluation de HAVING intervient pour filtrer le résultat de ces agrégations.
Voyons un exemple simple qui illustre cette logique. Imaginez que vous avez une table nommée étudiants avec des colonnes comme id, nom, et points. Si vous voulez connaître les groupes d’étudiants qui ont obtenu en moyenne plus de 90 points, vous ne pouvez pas faire ça en WHERE, car son rôle est de filtrer avant l’agrégation. Cela donnerait :
SELECT nom, MIN(points)
FROM étudiants
WHERE MIN(points) >= 90
GROUP BY nom;
Cela va générer une erreur, bien évidemment, car MIN(points) ne fait pas partie du jeu tant que le GROUP BY n’est pas appliqué.
En revanche, la bonne démarche serait de commencer par regrouper les étudiants, puis appliquer HAVING pour filtrer après :
SELECT nom, AVG(points)
FROM étudiants
GROUP BY nom
HAVING AVG(points) >= 90;
Voici un petit tableau comparatif pour mieux saisir les différences :
| Clause | Moment d’application | Utilisation |
|---|---|---|
| WHERE | Avant l’agrégation | Filtrer les enregistrements individuels |
| HAVING | Après l’agrégation | Filtrer les résultats agrégés |
La compréhension de ces subtilités vous donnera un net avantage lors des entretiens et vous évitera bon nombre d’erreurs gênantes. Ne laissez donc pas ces notions vous échapper, elles sont la clé pour dominer le monde du SQL.
Pourquoi privilégier les auto-jointures sur les sous-requêtes complexes
Les auto-jointures, ou self-joins, sont souvent mises de côté dans les discussions sur SQL. C’est pourtant une technique puissante, particulièrement lorsqu’il s’agit de comparer des lignes au sein de la même table. Prenons, par exemple, le cas des données temporelles. Ici, un self-join peut s’avérer des plus efficaces pour établir des relations entre différentes lignes d’un même tableau. Mieux encore, cette approche permet non seulement de rendre les requêtes plus lisibles, mais aussi de les optimiser en termes de performance.
En revanche, les sous-requêtes corrélées, bien qu’elles soient une fonction légitime dans le monde SQL, ont tendance à alourdir la complexité des requêtes. Elles rendent le code plus lourd et plus difficile à maintenir, car avec chaque exécution, elles doivent évaluer les résultats pour chaque ligne de l’ensemble de données, augmentant ainsi le temps de réponse. Le défi ici est d’optimiser la performance sans sacrifier la clarté – un équilibre parfois difficile à atteindre.
Examiner un exemple de comparaison entre une sous-requête et un self-join peut rendre ce point plus évident. Supposons que nous travaillons avec une table de taux de change où l’on souhaite comparer le taux du jour avec celui de la veille. Avec une sous-requête, cela pourrait ressembler à ceci :
SELECT date, taux
FROM taux_de_change AS t1
WHERE taux =
(SELECT taux FROM taux_de_change AS t2 WHERE t2.date = t1.date - INTERVAL 1 DAY);
En revanche, avec un self-join, la requête devient beaucoup plus directe :
SELECT t1.date, t1.taux, t2.taux AS taux_veille
FROM taux_de_change AS t1
JOIN taux_de_change AS t2 ON t1.date = t2.date + INTERVAL 1 DAY;
Visuellement et en termes de performance, la jointure se révèle plus simple et plus rapide. Voici un tableau qui résume les différences entre les deux techniques :
| Critères | Sous-requêtes | Auto-jointures |
|---|---|---|
| Lisibilité | Complexe | Claire |
| Performance | Moins efficace | Plus rapide |
| Cas d’usage | Situations spécifiques | Comparaison au sein d’une même table |
Pour plonger plus en profondeur sur ce sujet fascinant, n’hésitez pas à consulter cet article : source. Ce dernier soulève d’autres enjeux intéressants autour des jointures SQL et de leur utilisation judicieuse.
CTE ou sous-requêtes profondes que choisir en entretien SQL
Les CTE (Common Table Expressions) offrent une clarté et modularité qu’aucune cascade de sous-requêtes ne peut égaler, surtout en entretien où lisibilité et rapidité comptent. Imaginez-vous en train de maintenir une requête SQL qui aurait pu rendre un Saint en crise. Les sous-requêtes imbriquées, c’est un peu comme construire une tour de blocs : ça commence plutôt bien, mais à un moment donné, la structure devient tellement complexe que vous vous demandez qui a eu l’idée de commencer à empiler ces trucs.
Cette complexité grandit rapidement. Réfléchissez à cette question : comment classer des acteurs par genre dans une base de données géante remplie de films ? Utilisons un CTE simple pour cela :
WITH GenreActor AS (
SELECT a.name, g.genre
FROM actors a
JOIN movies m ON a.movie_id = m.id
JOIN genres g ON m.genre_id = g.id
)
SELECT genre, COUNT(name) AS actor_count
FROM GenreActor
GROUP BY genre;
Voilà, c’est limpide. Le CTE nous permet de nommer étape par étape, favorisant une compréhension immédiate comme s’il s’agissait d’un bon vieux scénario bien écrit. Maintenant, essayez d’imaginer la même logique, mais avec des sous-requêtes :
SELECT genre, COUNT(name) AS actor_count
FROM (
SELECT a.name,
(SELECT g.genre
FROM genres g
WHERE g.id = (SELECT m.genre_id
FROM movies m
WHERE m.id = a.movie_id)) AS genre
FROM actors a) AS GenreActor
GROUP BY genre;
Et voilà, on peut dire adieu à la lisibilité ! Ce côté alambiqué rend la maintenance presque impossible. Lorsque tu reviens sur ce code un mois plus tard pour ajouter un genre ou ajuster unparamètre, tu vas devoir faire appel à un détective pour comprendre ce qui se passe.
Les CTE permettent de découper les étapes clairement. Chaque étape est bien structurée et commentée, ce qui la rend facilement modifiable pour le futur. Dans un entretien, la capacité à présenter une solution claire est cruciale. Une approche limpide et directe à l’aide de CTE va non seulement impressionner ton interviewer mais aussi montrer ta compétence à travailler avec des données complexes sans perdre de vue la clarté.
En savoir plus sur les questions d’entretien SQL et renforcez vos compétences en matière de data.
Comment bien gérer les NULLs pour éviter les pièges SQL
NULL, c’est le vilain petit canard de SQL. Ce n’est pas une valeur, mais bien l’absence de valeur. Incroyable, non ? Cela fait tout un choc pour ceux qui s’imaginent que l’égalité va toujours de soi. Lorsque vous écrivez SELECT * FROM table WHERE column = NULL;, devinez quoi ? Ce n’est pas le bon chemin. La comparaison avec NULL ne fonctionnera jamais. Pourquoi ? Car NULL est un mystère incompris, une donnée qui dit « je ne sais pas » ou « cela ne s’applique pas ici ».
Pour traiter cette absence de données, il faut se tourner vers d’autres outils. Le premier est IS NULL. Utilisez-le avec parcimonie pour identifier les enregistrements qui n’ont vraiment pas de contenu. Par exemple, si vous cherchez à trouver les clients sans adresse e-mail, votre requête ressemblerait à ça :
SELECT * FROM clients WHERE email IS NULL;
Simple et efficace. Mais pour afficher des résultats de manière propre, il faut aller plus loin. Voici où COALESCE entre en jeu. Cette fonction va vous sauver la mise en remplissant les valeurs NULL avec un substitut. Imaginez un tableau de clients où certains n’ont pas de numéro de téléphone. Au lieu de laisser un vide désolant, vous pourriez dire :
SELECT name, COALESCE(phone, 'Non renseigné') as phone FROM clients;
Avec cette requête, pour tout numéro de téléphone manquant, vous obtiendrez « Non renseigné ». Ainsi, votre affichage est complet et soigné. Pensez à toutes les interactions que vous avez avec vos clients : un client qui ne reçoit pas d’appel parce que vous n’avez pas géré ces NULLs risque de ne jamais revenir.
En somme, voici un mini-guide de fonctions clés pour gérer les NULLs efficacement :
- IS NULL : pour tester si une valeur est NULL.
- IS NOT NULL : pour exclure les NULLs.
- COALESCE : pour remplacer les NULLs par la première valeur non NULL dans la liste.
- NULLIF : pour retourner NULL si deux valeurs sont égales.
La gestion des NULLs est un vrai défi, mais c’est un défi surmontable si l’on sait où chercher. En fin de compte, la bonne utilisation de ces fonctions peut transformer vos rapportings et interagir avec vos clients de manière proactive. Pour approfondir le sujet, n’hésitez pas à consulter cet article explicatif sur la gestion des NULLs en SQL.
Vous êtes prêt à maîtriser ces concepts SQL pour vos entretiens data ?
Ces six concepts SQL sont des pièges classiques en entretien data. Leur maîtrise exige plus que de la théorie : une compréhension précise et la pratique d’exemples concrets sont indispensables. En intégrant ces bonnes pratiques, vous évitez les erreurs fatales et démontrez votre rigueur technique, un vrai facteur de différenciation auprès des recruteurs. Ainsi préparé, vous abordez vos entretiens SQL avec sérénité et efficacité, multipliant vos chances de succès.
FAQ
Quels sont les problèmes les plus fréquents avec les fonctions fenêtrées en SQL ?
Pourquoi ne peut-on pas utiliser des agrégats dans WHERE ?
Quand privilégier une auto-jointure plutôt qu’une sous-requête ?
Quels avantages offrent les CTE par rapport aux sous-requêtes imbriquées ?
Comment gérer correctement les valeurs NULL en SQL ?
A propos de l’auteur
Je suis Franck Scandolera, consultant et formateur indépendant en Analytics et Data Engineering, avec plus de dix ans d’expérience en SQL et infrastructures data complexes. Fondateur de l’agence webAnalyste, j’accompagne et forme des professionnels à exploiter pleinement leurs données, de la collecte au reporting automatisé, en passant par l’optimisation des requêtes et la conformité RGPD. Mon expertise couvre BigQuery, Python, et l’intégration SQL dans des workflows data métier robustes et efficaces.
⭐ Analytics engineer, Data Analyst et Automatisation IA indépendant ⭐
- Ref clients : Logis Hôtel, Yelloh Village, BazarChic, Fédération Football Français, Texdecor…
Mon terrain de jeu :
- Data Analyst & Analytics engineering : tracking avancé (GTM server, e-commerce, CAPI, RGPD), entrepôt de données (BigQuery, Snowflake, PostgreSQL, ClickHouse), modèles (Airflow, dbt, Dataform), dashboards décisionnels (Looker, Power BI, Metabase, SQL, Python).
- Automatisation IA des taches Data, Marketing, RH, compta etc : conception de workflows intelligents robustes (n8n, App Script, scraping) connectés aux API de vos outils et LLM (OpenAI, Mistral, Claude…).
- Engineering IA pour créer des applications et agent IA sur mesure : intégration de LLM (OpenAI, Mistral…), RAG, assistants métier, génération de documents complexes, APIs, backends Node.js/Python.






