La plupart des candidats échouent sur des concepts SQL clés comme les fonctions fenêtrées, HAVING, les auto-jointures ou la gestion des NULLs. Voici un décryptage sans détour pour dominer ces pièges indispensables en interview, basé sur des cas concrets et vraies erreurs courantes.
3 principaux points à retenir.
- Comprendre et maîtriser les fonctions fenêtrées est indispensable pour éviter les résultats erronés et erreurs bloquantes.
- Différencier WHERE et HAVING dans le filtrage des résultats est clé face aux agrégations.
- Gérer les NULL efficacement évite des sorties incorrectes et facilite la garantie d’intégrité des données.
Pourquoi les fonctions fenêtrées posent-elles problème en entretien SQL
Les fonctions fenêtrées, vous connaissez ? Ces petits bijoux de SQL permettent d’effectuer des calculs dans un ensemble de lignes qui sont « fenêtrées » autour de la ligne en cours. Cependant, c’est ici que le bât blesse : beaucoup de candidats en entretien SQL galèrent avec ces fonctions. Pourquoi donc ? La réponse est souvent simple : une mauvaise compréhension du fonctionnement des fenêtres et des partitions, et surtout, cette fâcheuse tendance à oublier l’ORDER BY.
Imaginez que vous deviez détecter si un client a fait une deuxième vente dans un délai de 30 jours après sa première. Si on se lance sans préciser un ORDER BY dans nos fonctions comme LAG() ou LEAD(), on risque de recevoir des résultats qui ressemblent plus à un tirage de loto qu’à une analyse utile. Prenons un exemple concret :
SELECT client_id, vente_date,
LAG(vente_date) OVER (PARTITION BY client_id) AS derniere_vente
FROM ventes;
Cette requête, sans ORDER BY, peut retourner une derniere_vente qui ne respecte pas la chronologie ! Les résultats deviennent donc indéterministes et, spoiler alert, inutiles. Il est crucial d’ajouter cette directive :
SELECT client_id, vente_date,
LAG(vente_date) OVER (PARTITION BY client_id ORDER BY vente_date) AS derniere_vente
FROM ventes;
En ajoutant ORDER BY vente_date, on s’assure que les ventes sont traitées dans un ordre chronologique. Cela permet de détecter correctement les ventes successives.
Vous vous demandez peut-être pourquoi PostgreSQL autorise parfois des requêtes sans ORDER BY, tandis que d’autres SGBD comme MySQL ou SQL Server affichent une alerte. C’est simplement une question de philosophie de conception. PostgreSQL est plus permissif, laissant parfois les erreurs entrer dans la danse, ce qui peut mener à des analyses erronées. En revanche, d’autres systèmes bloquent ces requêtes pour mieux définir des normes de rigueur.
En fin de compte, le mantra est simple : n’oubliez jamais d’écrire un ORDER BY dans vos fonctions fenêtrées. Cela garantit des analyses fiables et évite de jouer à la roulette russe avec vos données.
Comment utiliser HAVING à bon escient face à WHERE avec agrégats
Dans le monde des bases de données, la distinction entre WHERE et HAVING est un véritable terrain miné pour beaucoup de candidats lors des entretiens. En effet, beaucoup croient encore que ces deux clauses sont interchangeables. Pourtant, la réalité est bien différente.
WHERE filtre les données avant l’agrégation, tandis que HAVING intervient après. En d’autres termes, WHERE est le garde-fou qui s’assure que seules les lignes pertinentes atteignent les étapes suivantes d’un traitement de données. Par contre, HAVING vient jouer son rôle une fois que les données ont été regroupées, permettant de poser des conditions sur ces agrégats. Une règle d’or ici : on ne peut pas utiliser d’agrégats dans une clause WHERE.
Imaginons un scénario courant : vous devez filtrer les joueurs ayant un score minimum. Voici une requête potentiellement erronée qui pourrait voir le jour :
SELECT equipe, MIN(points)
FROM joueurs
WHERE MIN(points) > 20
GROUP BY equipe;
Cette requête va générer une erreur. Pourquoi ? Tout simplement parce qu’on essaye d’utiliser la fonction d’agrégation MIN dans la clause WHERE, ce qui est illégal dans la syntaxe SQL. Cependant, la bonne manière d’approcher le problème serait :
SELECT equipe, MIN(points)
FROM joueurs
GROUP BY equipe
HAVING MIN(points) > 20;
Dans cette seconde requête, nous filtrons d’abord les données avec un GROUP BY, puis nous appliquons la condition sur l’agrégat à l’aide de HAVING. C’est simple, mais diablement puissant !
Ne pas comprendre cette nuance pourrait vous coûter cher lors d’un entretien, vous faisant perdre des points cruciaux. Un entretien peut se jouer sur ce genre de subtilités et, dans un environnement de production, cela peut provoquer des bugs majeurs. En somme, maîtriser la différence entre WHERE et HAVING est une nécessité, pas une option.
Pour en savoir plus sur cette distinction essentielle, n’hésitez pas à consulter cet article ici.
Pourquoi préférer les auto-jointures aux sous-requêtes complexes
Pourquoi préférer les auto-jointures aux sous-requêtes complexes
Quand on parle de requêtes SQL, la question des auto-jointures versus les sous-requêtes complexes est cruciale. La plupart des candidats, en entretien, penchent souvent pour la solution la plus élaborée. Cependant, ils passent à côté d’une approche plus simple, plus lisible et souvent plus performante : les auto-jointures. Regardons cela de plus près avec un exemple concret.
Imaginons que nous souhaitons calculer la variation d’un taux de change entre deux dates pour un même type de devise dans une table taux_de_change. Supposons que la structure de la table soit la suivante :
- id : identifiant du taux
- devise : nom de la devise
- valeur : valeur du taux de change
- date : date du taux
L’approche avec sous-requête imbriquée pourrait ressembler à ça :
SELECT
t1.devise,
(SELECT valeur FROM taux_de_change t2 WHERE t2.devise = t1.devise AND t2.date = '2021-01-01') -
(SELECT valeur FROM taux_de_change t3 WHERE t3.devise = t1.devise AND t3.date = '2021-01-31') AS variation
FROM
taux_de_change t1
WHERE
t1.date = '2021-01-01';
Intrigant, non ? Mais avouons-le, ça devient vite illisible et ça nécessite plusieurs passes dans la base de données. Et là, entre en jeu la magie de l’auto-jointure. Voici à quoi cela ressemble :
SELECT
t1.devise,
(t1.valeur - t2.valeur) AS variation
FROM
taux_de_change t1
JOIN
taux_de_change t2 ON t1.devise = t2.devise
WHERE
t1.date = '2021-01-01' AND t2.date = '2021-01-31';
Beaucoup plus clair, n’est-ce pas ? Non seulement la requête est plus concise, mais elle est aussi plus rapide. Les auto-jointures sont particulièrement pertinentes lorsque vous devez comparer des lignes d’une même table, comme pour des analyses chronologiques ou des comparaisons d’état.
En somme, opter pour une auto-jointure plutôt qu’une sous-requête complexe, c’est garantir une lisibilité accrue et des performances au rendez-vous. La prochaine fois que vous vous retrouvez à démontrer vos compétences SQL lors d’un entretien, pensez à élargir votre perspective et n’hésitez pas à mettre en avant cette approche. Vous pourriez bien impressionner votre interlocuteur. Pour en savoir plus sur les différences entre sous-requêtes et jointures, n’hésitez pas à consulter cet article ici.
À quoi servent les CTEs et comment améliorent-ils la lisibilité face aux sous-requêtes
Les Common Table Expressions (CTEs), c’est un peu le super-héros discret du SQL. Tu sais, ce genre de héros qui, tout en restant en retrait, illumine la situation de son génie. À quoi ça sert exactement ? En bref, les CTEs permetttent de structurer tes requêtes en étapes nommées. Imagine un chemin balisé dans une forêt d’imbrications de sous-requêtes : tu sais où tu vas et surtout, tu évites les détours pénibles.
Regarde cet exemple d’entretien, typique mais traître. Voici une requête qui cherche à identifier le top acteur par genre avec une multitude de sous-requêtes imbriquées :
SELECT genre, acteur
FROM (SELECT genre, acteur, RANK() OVER (PARTITION BY genre ORDER BY note DESC) AS rang
FROM (SELECT a.nom AS acteur, f.genre, AVG(e.note) AS note
FROM acteurs a
JOIN films f ON a.id = f.acteur_id
JOIN evaluations e ON f.id = e.film_id
GROUP BY a.nom, f.genre) AS sous_requete1) AS sous_requete2
WHERE rang = 1;
C’est un labyrinthe de complexité, et le pauvre candidat doit naviguer dans cet enchevêtrement. Mais imagine maintenant la même logique réécrite avec des CTEs :
WITH notes AS (
SELECT a.nom AS acteur, f.genre, AVG(e.note) AS note
FROM acteurs a
JOIN films f ON a.id = f.acteur_id
JOIN evaluations e ON f.id = e.film_id
GROUP BY a.nom, f.genre
),
rangs AS (
SELECT genre, acteur, RANK() OVER (PARTITION BY genre ORDER BY note DESC) AS rang
FROM notes
)
SELECT genre, acteur
FROM rangs
WHERE rang = 1;
Voilà, la magie des CTEs opère. La requête est maintenant aérée, chaque partie de la logique est identifiée clairement. Cela améliore la lisibilité et facilite la maintenance, surtout quand tu dois peaufiner ou corriger le tout. Si tu dois deboguer, c’est un véritable cadeau : tu peux tester chaque CTE individuellement sans t’y perdre. De plus, dans un contexte professionnel où les exigences changent rapidement, cette clarté permet à tout un chacun de plonger dans le code sans avoir à allumer un détecteur de fumée pour éviter les sous-requêtes qui combustent. Un vrai plaisir, non ?
Les CTEs ne sont pas juste une belle décoration syntaxique, ils incarnent une manière de penser et d’organiser le code qui peut véritablement faire la différence dans le quotidien d’un développeur SQL. Alors la prochaine fois que tu te situes dans une interview qui tourne mal à cause de requêtes trop complexes, rappelle-toi : la clarté a ses avantages !
Comment gérer correctement les valeurs NULL en SQL pour des résultats fiables
Vous pensez qu’un NULL, c’est juste un vide, un zéro, un « rien » ? Détrompez-vous. Dans le monde de SQL, NULL signifie « inconnu » ou « non applicable » et sa gestion est cruciale si vous voulez éviter de sérieux cafouillages. Utiliser = NULL dans une requête, c’est comme essayer de calculer des températures en utilisant des œufs : ça n’a tout simplement pas de sens.
Imaginez un instant que vous essayez de totaliser les interactions et les contenus d’une base de données clients. Certains clients ont interagi avec vos produits, d’autres ont acheté, mais il y a aussi ceux qui n’ont rien fait du tout. Résultat : si vous ne gérez pas les NULL, votre FULL OUTER JOIN peut vous donner une vue déformée. Certains clients, étant marqués par des NULL, ne seront pas comptabilisés correctement dans vos résultats. Et croyez-moi, des résultats incomplets, ça fait mal au business.
Pour palier à ce piège, il y a une solution élégante : COALESCE. Cette fonction vous permet de remplacer un NULL par une valeur par défaut. Par exemple, au lieu de voir un vide dans vos résultats, vous pouvez dire :
SELECT client_id, COALESCE(interactions, 0) AS total_interactions
FROM clients
FULL OUTER JOIN interactions ON clients.id = interactions.client_id;
Dans cet exemple, tous les clients seront visibles, même ceux qui n’ont pas interagi. Cela vous permet d’obtenir un rapport complet et précis. Une vraie bouffée d’air frais, n’est-ce pas ? Mon conseil : habituez-vous à utiliser COALESCE dès que vous manipulez des jointures externes. Cela devrait devenir un réflexe.
Vous voulez explorer davantage sur la gestion des données manquantes en SQL ? Découvrez des stratégies pertinentes sur ce site. En maîtrisant NULL, vous évitez des soucis d’interprétation dans vos résultats et vous ferez briller votre expertise en SQL. Les candidats qui comprennent ce concept font souvent la différence lors des entretiens.
Comment intégrer ces notions pour réussir vos entretiens SQL sans faute ?
Pour gagner vos entretiens SQL, maîtriser ces six concepts critiques est indispensable. Les fonctions fenêtrées mal paramétrées, le malentendu entre WHERE et HAVING, le choix inefficace entre auto-jointures et sous-requêtes, l’utilisation judicieuse des CTEs, ainsi que la bonne gestion des NULLs et la déduplication par groupe sont les zones où la majorité trébuche. Travailler ces points vous fournira une avance décisive, montrera votre vraie expertise et évitera de perdre des points sur des erreurs évitables. Vous repartez avec une méthodologie limpide et des exemples concrets pour ne plus jamais vaciller en entretien SQL.
FAQ
Qu’est-ce qu’une fonction fenêtrée en SQL et pourquoi est-elle délicate ?
Quelle est la différence entre WHERE et HAVING ?
Pourquoi privilégier les auto-jointures aux sous-requêtes imbriquées ?
Quels avantages apportent les Common Table Expressions (CTEs) ?
Comment gérer efficacement les valeurs NULL en SQL ?
A propos de l’auteur
Je suis Franck Scandolera, Analyste et consultant expert en Analytics et Data Engineering depuis plus de dix ans, responsable de l’agence webAnalyste et formateur certifié à travers la France et la francophonie. Ma pratique intensive du SQL dans des contextes exigeants — suivi d’infrastructures data, automatisation, analyses avancées — m’a exposé aux pièges et bonnes pratiques que je transmets rigoureusement lors de mes formations en Data et Web Analytics. J’accompagne les professionnels à structurer efficacement leurs données, éviter les erreurs fréquentes et tirer profit d’un SQL propre et performant pour leurs business.
⭐ 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.






