Home » Analytics » Quels sont les concepts SQL souvent ratés en entretien data ?

Quels sont les concepts SQL souvent ratés en entretien data ?

Les candidats échouent fréquemment sur six concepts clés SQL lors d’entretiens data : fonctions fenêtres, filtres avec agrégats, auto-jointures, CTE vs sous-requêtes, gestion des NULLs et déduplication par groupe. Comprendre ces points précis augmente nettement vos chances de réussite.

3 principaux points à retenir.

  • Maîtriser les fonctions fenêtres exige de bien ordonner et partitionner les données.
  • Savoir distinguer WHERE et HAVING est fondamental pour filtrer les agrégats correctement.
  • La gestion des NULLs et la déduplication nécessitent des techniques spécifiques comme COALESCE() et RANK().

Pourquoi les fonctions fenêtres posent-elles problème en entretien SQL

Les fonctions fenêtres en SQL, c’est un peu comme un vaste océan pour un novice en natation : fascinant mais gênant s’il n’est pas maîtrisé. Beaucoup de professionnels ratent le coche lors des entretiens parce qu’ils ne saisissent pas l’importance de l’usage correct de PARTITION BY, ORDER BY et des frames. Commençons par mettre les pieds dans le plat : l’absence d’ORDER BY dans l’utilisation de la fonction LAG() peut entraîner des résultats aléatoires. La question qui se pose est simple : comment s’y retrouver alors ?

Imaginons une base de données d’achats avec des utilisateurs ayant effectué plusieurs transactions. Si l’on essaie de déterminer si un utilisateur a fait un second achat dans la semaine suivant son premier, voici le mauvais exemple de code :

SELECT user_id,
       purchase_date,
       LAG(purchase_date) OVER (PARTITION BY user_id) AS previous_purchase
FROM purchases;

Sans ORDER BY, LAG() va juste tirer les dates d’achat des places au hasard, et donc on s’expose à un chaos total dans les résultats. Résultat : les interviews peuvent mal tourner et le candidat se retrouve coincé sur une question cruciale.

Pour corriger cela, il nous faut un peu de discipline dans notre requête. Voici l’exemple corrigé:

SELECT user_id,
       purchase_date,
       LAG(purchase_date) OVER (PARTITION BY user_id ORDER BY purchase_date) AS previous_purchase
FROM purchases
WHERE previous_purchase IS NOT NULL AND
      DATEDIFF(purchase_date, previous_purchase) 

Dans cette requête, PARTITION BY va diviser les données utilisateur, et ORDER BY s’assure que nous regardons bien les achats dans l’ordre chronologique. Ça nous permettra d’identifier de façon précise et fiable qui a effectué un second achat dans les 7 jours suivant le premier.

Pour vous éviter des faux pas, voici un tableau récapitulatif des erreurs courantes à éviter avec les fonctions fenêtres :

  • Oublier d'utiliser ORDER BY : entraîne des résultats aléatoires.
  • Ne pas utiliser de partition : on perd la logique de regroupement.
  • Ne pas analyser les frames : peut mener à des calculs erronés.

Comment bien filtrer avec WHERE et HAVING sur des agrégats

Un truc que beaucoup de candidats ratent en entretien data, c'est la subtilité entre WHERE et HAVING. Premier constat : on ne peut pas utiliser des agrégats dans la clause WHERE. Pourquoi ? Simple, l’ordre d’exécution SQL place la déclaration WHERE avant le moment où les données sont agrégées. On ne peut donc pas l’utiliser pour filtrer des résultats qui nécessitent un traitement d’agrégation comme MIN(), MAX() ou AVG().

La différence entre WHERE et HAVING se résume essentiellement à leur timing.

  • WHERE : filtre les données avant qu'elles ne soient agrégées.
  • HAVING : filtre les données après l’agrégation.

Imaginons qu’on veuille afficher des équipes et leur score, mais seulement celles qui ont un score minimum de 100. Voici un petit exemple pour clarifier le concept.

Mauvaise approche :

SELECT équipe, MIN(score) 
FROM matchs 
WHERE MIN(score) > 100 
GROUP BY équipe;

Ce code fait fausse route. Il cherche à filtrer en amont avec WHERE, ce qui n'est pas possible ici. La bonne façon de procéder serait d’utiliser HAVING :

SELECT équipe, MIN(score) 
FROM matchs 
GROUP BY équipe 
HAVING MIN(score) > 100;

Ce dernier exemple fonctionne. Les données sont d’abord regroupées par équipe, puis le filtrage s’effectue sur ces valeurs agrégées. Voilà un point important à garder à l’esprit lors de vos entretiens.

Pour récapituler tout cela, voici un tableau comparatif pour bien visualiser les différences :

Caractéristique WHERE HAVING
Moment d'exécution Avant l’agrégation Après l’agrégation
Filtre sur agrégats Non Oui
Utilisation commune Filtrage des lignes individuelles Filtrage des résultats agrégés

Les règles à respecter pour filtrer sur des agrégats sont simples : utilisez ALWAYS HAVING pour les agrégats, évitez d'utiliser WHERE pour ces derniers, et souvenez-vous que l'ordre d'exécution est fondamental dans SQL.

Pourquoi privilégier les auto-jointures pour les comparaisons temporelles

On pourrait penser qu'une auto-jointure, c’est un peu comme un match de boxe entre deux versions de soi-même dans le ring des données, non ? Mais détrompez-vous, c'est bien plus qu'un simple duel. Joindre une table à elle-même est une solution élégante pour des comparaisons temporelles, surtout quand il s'agit de jongler avec des événements. Imaginez que vous deviez analyser le taux de change à deux dates différentes. Plutôt que d'utiliser un sous-sélect, qui transformerait votre requête en un véritable casse-tête, l'auto-jointure simplifie le tableau. Considérez cela.

Par exemple, imaginons que nous voulions comparer le taux de change de l’euro par rapport au dollar à deux moments précis : le 1er janvier 2021 et le 1er janvier 2022.
Voici comment une auto-jointure vous sauverait la mise :

SELECT 
    a.date AS date_2021, 
    a.taux AS taux_2021, 
    b.date AS date_2022, 
    b.taux AS taux_2022,
    (b.taux - a.taux) AS difference
FROM 
    taux_de_change AS a
JOIN 
    taux_de_change AS b 
ON 
    a.date = '2021-01-01' 
    AND b.date = '2022-01-01';

Dans cet exemple, on analyse deux lignes de la même table en ne changeant qu'un seul alias. Résultat : une requête claire et concise, sans labyrinthes de sous-requêtes. En gros, l'auto-jointure permet de comparer directement les données d’une même table de façon intuitive.

Mais qu'en est-il des sous-requêtes corrélées ? Elles peuvent devenir de véritables pièges à performance. Pour illustrer, voici un tableau comparatif entre ces deux méthodes :

Méthode Performance Clarté
Sous-requêtes corrélées ⚠️ Lente 🌀 Complexe
Auto-jointures ✅ Efficace ✅ Claire

Conclusion : en matière de requêtes SQL, mieux vaut parfois se fier à la simplicité d’une danse en solitaire avec soi-même, qu'à des enchevêtrements d'idées. Alors, pour vos prochaines comparaisons temporelles, pensez à l'auto-jointure, votre alliée secrète dans le monde des données.

Quand et pourquoi préférer les CTE aux sous-requêtes imbriquées

Travailler avec des requêtes SQL, c’est un peu comme jongler avec des flammes. L’objectif est de maîtriser l’art sans se brûler les ailes mais, parfois, on finit par s’embrouiller. Prenons un exemple concret : vous devez extraire des informations sur des acteurs et leurs genres, en calculant la moyenne de notes. Cela semble simple, mais sans les bons outils, cela peut vite devenir un véritable casse-tête. Imaginez deux approches : l’une avec des CTE (Common Table Expressions) et l’autre avec des sous-requêtes à la limite de la lisibilité.

Voici ce que pourrait donner votre code avec des CTE :

WITH ActorGenres AS (
    SELECT ActorID, GenreID
    FROM ActorGenre
), RatingAverage AS (
    SELECT ActorID, AVG(Rating) AS AvgRating
    FROM Movies
    GROUP BY ActorID
)
SELECT a.ActorID, ag.GenreID, ra.AvgRating
FROM ActorGenres ag
JOIN RatingAverage ra ON ag.ActorID = ra.ActorID;

Claire, directe, presque linéaire, cette version permet de démêler les relations entre différentes tables sans perdre le lecteur. On peut facilement identifier chaque partie grâce aux CTE. Les noms explicites rendent le tout compréhensible, et chaque section peut être ajustée indépendamment du reste.

À l’inverse, regardons la version calamiteuse avec des sous-requêtes imbriquées :

SELECT a.ActorID, 
       (SELECT g.GenreID FROM ActorGenre g WHERE g.ActorID = a.ActorID) AS GenreID,
       (SELECT AVG(m.Rating) FROM Movies m WHERE m.ActorID = a.ActorID) AS AvgRating
FROM Actors a;

Ça pique, n’est-ce pas ? Ici, on nage dans une mer de parenthèses et d'imbrications ! Chaque sous-requête renferme un monde à part entière, ce qui rend la maintenance et la compréhension du tout extrêmement ardue. Le fait de devoir relire plusieurs fois pour saisir les nuances, c'est chronophage et c'est ici que les CTE brillent. Imaginez une équipe essayant de déboguer ce dernier monument à la complexité. Un vrai cauchemar de communication entre développeurs.

En résumé, voici un tableau synthèse :

  • CTE :
    • Clarté et lisibilité
    • Facilité de modification
    • Modularité des requêtes
  • Sous-requêtes :
    • Complexité accrue
    • Lisibilité limitée
    • Difficulté dans la maintenance

Utiliser des CTE, c’est choisir la voie de la sagesse. Cela rappelle cette citation de Confucius : « La simplicité est la clé de la vraie sophistication. » Alors, pourquoi ne pas l'appliquer dans vos requêtes SQL ? Pour approfondir, je vous invite à lire cet article sur les CTE et les sous-requêtes.

Comment gérer efficacement les NULLs dans vos requêtes SQL

Gérer les NULLs dans vos requêtes SQL, c'est un peu comme jongler avec des œufs : si un seul est cassé, tout le spectacle tombe à l'eau. Pourquoi ? Parce que dans SQL, NULL ne signifie pas "vide", ça signifie "inconnu". En d'autres termes, NULL n’est équivalent à rien, pas même à lui-même. Surprenant, non ? Cette caractéristique peut rapidement faire sauter la logique conditionnelle que vous croyez maîtriser.

Quand vous effectuez des filtrages dans vos requêtes, vous devez savoir qu’utiliser un simple égal à (=) pour comparer avec NULL ne donnera jamais le résultat escompté. Au lieu de ça, vous devez avoir recours à IS NULL. C'est la clé pour filtrer efficacement vos données contenant des valeurs NULL sans flinguer vos résultats. Et ne sous-estimez pas la puissance de la fonction COALESCE(). Elle est là pour vous sauver la mise, transformant ces NULLs en valeurs par défaut intelligentes, permettant ainsi de maintenir l’intégrité de vos résultats.

Imaginons un scénario classique : vous faites une jointure FULL OUTER JOIN entre deux tables, disons clients et interactions. Vous êtes en train de comptabiliser le nombre d'interactions pour chaque client et, surprise, vous vous retrouvez avec des NULL dans votre résultat. Si vous ne gérez pas ces NULLs correctement, vous pouvez perdre des informations cruciales sur la relation entre vos tables.

SELECT c.client_id, 
       COUNT(i.interaction_id) AS total_interactions
FROM clients c
FULL OUTER JOIN interactions i ON c.client_id = i.client_id
GROUP BY c.client_id;

Ce code vous laisse avec des NULL pour les clients qui n'ont jamais eu d'interactions. En conséquence, le total des interactions sera plombé. Pour corriger cela, voici la solution avec COALESCE() :

SELECT c.client_id, 
       COALESCE(COUNT(i.interaction_id), 0) AS total_interactions
FROM clients c
FULL OUTER JOIN interactions i ON c.client_id = i.client_id
GROUP BY c.client_id;

Ce que vous faites ici, c'est plutôt simple : vous remplacez tout NULL résultant de l'absence d’interactions par un 0, garantissant ainsi des données plus fiables.

Pour finir, un petit récapitulatif qui pourrait vous éclaircir davantage sur le traitement des NULLs :

  • IS NULL : pour tester si une valeur est NULL.
  • IS NOT NULL : pour tester si une valeur n'est pas NULL.
  • COALESCE(expr1, expr2, ...) : retourne la première valeur non NULL.
  • NULLIF(expr1, expr2) : retourne NULL si les deux expressions sont égales.

Prêt à maîtriser ces concepts pour réussir votre entretien SQL data ?

Les six concepts SQL détaillés — fonctions fenêtres, filtres HAVING, auto-jointures, CTE, gestion des NULLs et déduplication par groupe — sont des écueils classiques qui font tomber même les candidats expérimentés. Les comprendre en profondeur, pratiquer les bons réflexes et savoir les appliquer clairement dans vos requêtes sont des garanties solides pour réussir vos entretiens data. Adopter ces bonnes pratiques vous démarquera, évitera les erreurs gênantes et améliorera votre productivité SQL en conditions réelles. C’est un investissement clair dans votre employabilité et crédibilité professionnelle.

FAQ

Quelles sont les erreurs courantes avec les fonctions fenêtres en SQL ?

Ne pas spécifier ORDER BY dans les fonctions LAG(), LEAD() ou les fonctions de classement entraîne des résultats aléatoires et non déterministes.

Pourquoi ne pas utiliser d'agrégats dans WHERE ?

La clause WHERE filtre les lignes avant l’agrégation. Les fonctions d’agrégat ne sont calculées qu’après cet étape, il faut donc utiliser HAVING pour filtrer sur des agrégats.

Quand utiliser une auto-jointure en SQL ?

Pour comparer des lignes d’une même table entre elles, notamment des données datées à des périodes différentes, l’auto-jointure est plus simple, claire et efficiente que des sous-requêtes corrélées.

Que privilégier entre CTE et sous-requêtes ?

Les CTE sont préférables pour des requêtes complexes avec plusieurs étapes, améliorant la lisibilité et la maintenance, contrairement aux sous-requêtes imbriquées qui peuvent devenir illisibles.

Comment bien gérer les valeurs NULL en SQL ?

Il faut utiliser IS NULL pour tester NULL, ne jamais utiliser = NULL, et COALESCE() pour remplacer NULL par une valeur par défaut afin d’éviter des résultats incomplets.

 

 

A propos de l'auteur

Franck Scandolera, fort de plus de dix ans d’expérience comme consultant et formateur en Data Engineering, Analytics et SQL, accompagne des professionnels en France, Suisse et Belgique. Responsable de l’agence webAnalyste et de « Formations Analytics », il maîtrise l’intégration et l’automatisation des données via SQL, Python et outils cloud. Spécialiste reconnu des bonnes pratiques SQL, Franck forme et conseille pour rendre la donnée accessible, exploitable et conforme, garantissant aux équipes la robustesse indispensable pour les défis business.

Retour en haut
Data Data Boom