Home » Analytics » Quels concepts SQL échouent les candidats en entretien data ?

Quels concepts SQL échouent les candidats en entretien data ?

Les candidats échouent souvent sur six concepts SQL clés en entretien data : fonctions fenêtres, filtrage avec agrégats, auto-jointures, CTE vs sous-requêtes, gestion des NULLs, et déduplication groupée. Comprendre et maîtriser ces notions accroît vos chances de réussite.

3 principaux points à retenir.

  • Les fonctions fenêtres demandent un ordre explicite pour produire des résultats corrects.
  • La clause HAVING filtre après agrégation, contrairement à WHERE.
  • CTEs rendent les requêtes complexes plus lisibles et maintenables.

Pourquoi les fonctions fenêtres posent-elles problème ?

Les fonctions fenêtres dans SQL, c’est un peu comme la magie des chiffres, mais voilà, trop de candidats se retrouvent sur les planches et donnent du spectacle au lieu de sortir leurs véritables talents. Pourquoi ? Parce qu’ils oublient l’une des règles fondamentales : la clause ORDER BY. C’est vraiment LE point de friction qui fait souvent chuter les performances en entretien data. Sans ORDER BY, tes résultats deviennent totalement chaotiques, arbitraires, et tu perds la finesse qu’offre cette fonctionnalité.

Pense à des fonctions comme LAG() ou LEAD(), sans un bon ORDER BY, on se retrouve vite à jongler avec des informations qui n’ont ni queue ni tête. Imaginons un cas où tu cherches à trouver un achat effectué dans les 7 jours suivant un précédent. Si tu ne spécifies pas comment trier les données, tu obtiens des résultats qui ne signifient rien. Un peu comme si tu essayais de lire un livre sans en respecter l’ordre des chapitres !

Pour illustrer ça, voici une erreur classique et sa correction :


-- Mauvaise requête sans ORDER BY
SELECT 
    customer_id, 
    purchase_date,
    LAG(purchase_date) OVER (PARTITION BY customer_id) AS previous_purchase
FROM 
    purchases;

-- Bonne requête avec ORDER BY
SELECT 
    customer_id, 
    purchase_date,
    LAG(purchase_date) OVER (PARTITION BY customer_id ORDER BY purchase_date) AS previous_purchase
FROM 
    purchases;

Dans la seconde requête, en ajoutant ORDER BY purchase_date, tu garantis que LAG() renvoie la date d’achat correcte. Cela t’assure que, peu importe combien de données tu as, tu cuirais toujours correctement le timing entre les achats.

Éviter cette confusion renforce non seulement la fiabilité de tes résultats mais te permet également de briller dans un entretien. Tu démontres ainsi que tu comprends le cadre d’exécution et que tu sais comment manipuler les données avec précision. Et qui dit précision, dit confiance, et qui dit confiance, dit chances d’embauche !

Quelle est la différence entre WHERE et HAVING ?

La distinction entre WHERE et HAVING est souvent floue pour beaucoup, et cette confusion peut coûter cher lors d’un entretien. En effet, une seule requête peut susciter des erreurs embarrassantes. Alors, clarifions cela. WHERE s’applique avant la phase d’agrégation des données, tandis que HAVING agit après cette agrégation. Si vous essayez d’utiliser une fonction d’agrégat dans une clause WHERE, vous allez droit dans le mur !

Examinons le cycle d’exécution typique d’une requête SQL, qui se déroule comme suit :

  • FROM
  • WHERE
  • GROUP BY
  • HAVING
  • SELECT

Pour illustrer l’erreur commune, prenons un exemple. Supposons que nous souhaitons récupérer le nom des équipes avec un score minimal de 10 points. Une requête mal formulée serait :

SELECT team_name, MIN(points)
FROM games
WHERE MIN(points) > 10
GROUP BY team_name;

Ici, l’usage de MIN(points) dans WHERE va provoquer une erreur. Pourquoi ? Parce que WHERE ne peut pas filtrer les résultats agrégés. En fait, le filtre doit être appliqué à l’étape HAVING. Voyons la requête correcte :

SELECT team_name, MIN(points)
FROM games
GROUP BY team_name
HAVING MIN(points) > 10;

Dans ce cas, nous regroupons d’abord les points par équipe et ensuite, nous appliquons le filtre pour ne garder que celles qui ont un score minimum supérieur à 10. C’est d’une simplicité redoutable, mais tant de candidats se plantent sur cette subtilité.

Pour renforcer cette compréhension, il est utile de se rappeler que les fonctions d’agrégat sont surtout conçues pour être utilisées avec HAVING, car cette clause s’exécute après que le groupe a été formé. En maîtrisant cette distinction, vous serez non seulement plus compétent en SQL, mais également mieux préparé pour impressionner vos recruteurs. Pour une lecture complémentaire sur la différence entre WHERE et HAVING, cliquez ici.

Comment utiliser les auto-jointures pour comparer des événements ?

Les auto-jointures, ou self-joins, sont souvent sous-estimées par les candidats lors des entretiens pour des postes liés aux données. Pourtant, ces requêtes qui consistent à joindre une table à elle-même peuvent s’avérer être des alliées redoutables, notamment pour comparer des événements dans le temps. Pourquoi en parler ? Parce qu’elles sont souvent mieux adaptées que des sous-requêtes imbriquées, tant en lisibilité qu’en performance.

Imaginons par exemple que nous travaillons avec une table des taux de change. Si nous souhaitons comparer les taux à deux dates différentes, une auto-jointure pourrait sembler la solution évidente. Prenons une table nommée exchange_rates avec les colonnes currency, rate et date.

Voici comment une sous-requête complexe pourrait être formulée pour le même objectif :

SELECT 
    e1.currency, 
    e1.rate AS rate_on_date1, 
    (SELECT rate 
     FROM exchange_rates e2 
     WHERE e2.currency = e1.currency 
     AND e2.date = '2023-01-01') AS rate_on_date2 
FROM exchange_rates e1 
WHERE e1.date = '2023-01-02';

Ce code, bien que valide, présente une complexité qui pourrait faire perdre du temps inutilement. Maintenant, passons à notre auto-jointure :

SELECT 
    e1.currency, 
    e1.rate AS rate_on_date1, 
    e2.rate AS rate_on_date2 
FROM exchange_rates e1 
JOIN exchange_rates e2 ON e1.currency = e2.currency 
WHERE e1.date = '2023-01-02' 
AND e2.date = '2023-01-01';

En utilisant l’auto-jointure, on simplifie notre requête tout en améliorant la lisibilité. Chaque élément est directement issu de la même table, évitant les fouillis d’imbrications qui rendent la maintenance du code plus chaotique.

En plus de la clarté, une auto-jointure est souvent plus performante. Le moteur de base de données peut optimiser les jointures de manière plus efficace que les imbroglios de sous-requêtes. C’est un faux ami que de penser que les sous-requêtes sont toujours plus simples. Alors, la prochaine fois que vous devrez analyser une évolution dans le temps ou toute autre comparaison d’enregistrements au sein d’une même table, pensez à l’auto-jointure comme à votre fidèle compagne.

Pour une plongée plus profonde sur le sujet, la lecture de cet article pourrait vous éclairer encore plus sur les relations hiérarchiques en SQL.

Pourquoi privilégier les CTEs aux sous-requêtes imbriquées ?

Quand il s’agit de requêtes SQL complexes, la question qui revient souvent est : faut-il utiliser des Common Table Expressions (CTEs) ou se perdre dans les méandres des sous-requêtes imbriquées? C’est un peu comme choisir entre un bon verre de vin et un cocktail explosif. Le vin, c’est beau, c’est clair, ça coule tout seul, tandis que le cocktail…le cocktail peut vous exploser à la figure si vous n’y prêtez pas attention !

Les CTEs, grâce à la syntaxe WITH, permettent de rendre les requêtes lisibles comme un bon roman, tandis que les sous-requêtes imbriquées peuvent rapidement devenir un véritable cauchemar de maintenabilité. Imaginez vos collègues essayant de décortiquer une sous-requête de plusieurs niveaux… Ça devient vite une séance de désencombrement de code. La clarté d’une CTE vous permet de réutiliser des requêtes sans la redondance qui alourdit les sous-requêtes imbriquées. En fait, une bonne CTE devient presque poétique.

Pour illustrer cela, prenons un cas concret : nous souhaitons calculer les top acteurs par genre à partir de données regroupées. Voici comment cela se présente en CTE :

WITH GenreStats AS (
    SELECT 
        genre,
        acteur,
        COUNT(*) AS nombre_films
    FROM films
    GROUP BY genre, acteur
)
SELECT 
    genre, 
    acteur, 
    nombre_films 
FROM GenreStats 
ORDER BY genre, nombre_films DESC;

Voici la même logique avec une sous-requête imbriquée :

SELECT 
    genre, 
    acteur, 
    COUNT(*) AS nombre_films 
FROM (
    SELECT 
        genre, 
        acteur 
    FROM films 
) AS SousRequete 
GROUP BY genre, acteur 
ORDER BY genre, nombre_films DESC;

Dans cet exemple, la version avec CTE est non seulement plus lisible, mais elle permet aussi d’éviter la duplication de logiques, ce qui est un point essentiel dans la maintenabilité du code SQL.

La leçon ici est simple : lorsque vous rencontrez une requête complexe, n’oubliez pas que la clarté et la maintenabilité sont primordiales. Optez pour les CTEs, elles vous feront gagner un temps précieux, tant lors de la création que lors de la relecture. En somme, choisissez la clarté d’esprit plutôt que le tumulte des sous-requêtes

Comment gérer correctement les NULLs dans SQL ?

Dans le monde SQL, le NULL est un petit mais redoutable monstre. Qui aurait cru qu’un simple mot pouvait causer tant de tracas ? La première leçon à apprendre, c’est que NULL n’est égal à rien, même pas à NULL. Oui, vous avez bien entendu. Si un candidat répond à une question en utilisant = NULL pour tester des valeurs NULL, la seule chose qu’il peut récolter, c’est un regard désabusé de l’intervieweur. Pourquoi ? Parce qu’en SQL, un test de valeur NULL doit être effectué avec IS NULL ou IS NOT NULL pour vérifier si une valeur est absente.

Imaginez que vous ayez deux tables qui contiennent des informations sur des clients et des commandes. Si vous réalisez un FULL OUTER JOIN entre ces deux tables, vous risquez d’être envahi par des NULLs, surtout si certains clients n’ont pas passé de commandes. Prenons un exemple concret :

SELECT c.client_id, COUNT(o.order_id) AS order_count
FROM clients c
FULL OUTER JOIN orders o ON c.client_id = o.client_id
GROUP BY c.client_id;

Dans ce cas, lorsque certains clients n’ont pas de commandes associées, order_count renverra des NULLs, ce qui n’est pas ce que nous voulons. Que faire alors ? C’est là que COALESCE() entre en jeu. Cette fonction permet de prendre le premier argument non NULL d’une liste donnée. Voici comment vous pourriez utiliser COALESCE pour gérer ça :

SELECT c.client_id, COALESCE(COUNT(o.order_id), 0) AS order_count
FROM clients c
FULL OUTER JOIN orders o ON c.client_id = o.client_id
GROUP BY c.client_id;

En utilisant COALESCE ici, si l’utilisateur n’a pas passé de commande, nous le remplaçons par 0 au lieu d’un NULL. Cela nous permet de garder constamment des compteurs et identifiants propres et compréhensibles. La gestion des NULLs est cruciale, et ne pas le faire correctement peut mener à des rapports erronés ou à des erreurs dans les analyses de données. Si vous souhaitez approfondir ce sujet, je vous recommande de jeter un coup d’œil à cet article sur la gestion des NULLs.

Comment dédupliquer des groupes en sélectionnant la meilleure ligne ?

Dédupliquer des groupes en sélectionnant la meilleure ligne selon un critère peut sembler être un casse-tête pour beaucoup de candidats lors des entretiens data. Mettons les choses au clair : la solution de facilité, qui consiste à utiliser GROUP BY associé à LIMIT, n’est pas la panacée. En fait, elle échoue souvent là où on l’attendrait le moins.

Imaginons que vous devez trouver le meilleur produit vendu chaque mois, selon les ventes totales. La méthode GROUP BY avec LIMIT 1 pourrait sembler suffisante sur le papier, mais en réalité, elle peut vous jouer des tours. Si vous avez plusieurs produits vendus avec la même somme de ventes pour un mois donné, cette méthode ne saura pas choisir efficacement entre eux. Le résultat pourrait être biaisé, omettant certains produits ayant atteint le même sommet de ventes.

Voici un exemple concret. Supposons que nous avons une table ventes contenant les colonnes produit, mois, et total_ventes :


produit   | mois      | total_ventes
---------- | --------- | -------------
Produit A | 2023-01  | 500
Produit B | 2023-01  | 500
Produit C | 2023-01  | 300
Produit D | 2023-02  | 600
Produit E | 2023-02  | 450

En utilisant GROUP BY et LIMIT, vous obtiendrez un seul résultat par mois, sans garantie que vous attrapiez le meilleur des meilleurs. Pour éviter cela, nous passons à la vitesse supérieure avec les fonctions de classement.

Utiliser RANK() dans une sous-requête est le bon chemin à suivre. Voici comment procéder :


SELECT produit, mois, total_ventes
FROM (
    SELECT produit, mois, total_ventes,
           RANK() OVER (PARTITION BY mois ORDER BY total_ventes DESC) AS rnk
    FROM ventes
) AS sous_requete
WHERE rnk = 1;

Cette requête attribue un rang à chaque produit par mois. En spécifiant WHERE rnk = 1, vous obtenez tous les produits qui partagent le même total de ventes le plus élevé, gérant ainsi les égalités de manière élégante.

En somme, recourir à RANK() vous permet de façonner vos résultats sans compromettre l’intégrité des données. Cela pourrait ne pas être la première solution à laquelle pensent les personnes que vous interrogez, mais une fois maîtrisée, cette technique est un atout indéniable dans votre arsenal SQL.

Comment ces méthodes SQL vont-elles booster vos performances en entretien ?

Maîtriser ces six concepts SQL – fonctions fenêtres bien ordonnées, bon usage de HAVING, auto-jointures, CTEs pour la clarté, gestion intelligente des NULLs et déduplication avec fonctions de classement – est indispensable pour réussir vos entretiens data. Ces notions sont des pièges classiques où beaucoup trébuchent, mais elles restent incontournables à comprendre et pratiquer. En les intégrant, vous gagnerez en efficacité, fiabilité et maintenabilité dans vos requêtes. Ce sont ces compétences qui feront la différence face aux recruteurs exigeants et vous ouvriront les portes des postes data stratégiques.

FAQ

Pourquoi les fonctions fenêtres nécessitent-elles un ORDER BY dans SQL ?

Sans ORDER BY, les fonctions fenêtres comme LAG() ou LEAD() comparent les lignes dans un ordre arbitraire, menant à des résultats incorrects ou non déterministes. L’ORDER BY définit explicitement l’ordre de la fenêtre, garantissant un calcul fiable.

Quelle est la différence entre WHERE et HAVING en SQL ?

WHERE filtre les lignes avant l’agrégation des données, HAVING les filtre après. Les fonctions d’agrégat comme SUM() ou MIN() ne peuvent donc pas être utilisées dans WHERE, mais uniquement dans HAVING.

Quand faut-il utiliser une auto-jointure en SQL ?

Une auto-jointure est utile pour comparer des lignes d’une même table, par exemple pour analyser des événements ou états successifs d’un utilisateur dans le temps, souvent plus claire et performante que des sous-requêtes imbriquées.

Pourquoi privilégier les CTEs au lieu des sous-requêtes imbriquées ?

Les CTEs offrent une meilleure lisibilité, structure le code en étapes claires, et facilitent la maintenance. En comparaison, les sous-requêtes imbriquées peuvent devenir illisibles et redondantes, compliquant la compréhension et les modifications ultérieures.

Comment gérer les NULLs pour éviter les erreurs en SQL ?

NULL ne peut être comparé avec = NULL, il faut utiliser IS NULL pour tester une valeur nulle. Pour éviter la propagation de NULL dans les résultats, COALESCE() permet de remplacer NULL par une valeur par défaut, comme 0 ou une chaîne vide.

 

 

A propos de l’auteur

Franck Scandolera, fort d’une longue expérience de consultant et formateur en analytics et Data Engineering, accompagne professionnels et entreprises dans la maîtrise avancée de SQL et des infrastructures data. Responsable de l’agence webAnalyste, expert en automatisation et IA, il vulgarise et transmet des compétences techniques pointues pour transformer les données en leviers d’action concrets.

Retour en haut
DataMarket AI