💡 SQL : Comprendre au lieu d’appliquer par cœur

SQL est l’un des langages les plus populaires au monde. Mais soyons honnêtes : il est très facile d’appliquer des requêtes apprises par cœur, sans vraiment comprendre ce qui se passe en arrière-plan. Résultat : quand une requête ne marche pas ou qu’un résultat semble incohérent, on se retrouve vite à tourner en rond. Prenons un exemple : ```markdown SELECT COUNT(*) AS nb_singers_users FROM Singer AS S WHERE nb_singers_users>4; ``` Saviez-vous que cette requête est susceptible de planter dans certains contextes ? Ce n’est pas qu’une question de syntaxe : l’ordre dans lequel vous écrivez votre requête n’est pas l’ordre dans lequel le moteur SQL l’exécute. Dans mon article, je vous explique : 🔹 L’ordre d’exécution réel des requêtes SQL (et pourquoi ça compte). 🔹 Le rôle du JOIN ... ON (bien plus qu’une simple liaison entre clés étrangères). 🔹 Pourquoi un GROUP BY peut déclencher des erreurs et la règle pour l’utiliser correctement. 🔹 Comment écrire des JOIN robustes et éviter les pièges classiques. Mon objectif : vous aider à penser SQL plutôt que de simplement recopier des formules. 🚀 Place à l'explication : Beaucoup de requêtes « marchent »… jusqu’au jour où elles ne marchent plus. La différence entre un copier-coller et une requête robuste tient à une chose : comprendre l’ordre logique d’exécution et ce que fait vraiment chaque clause. 1) L’ordre logique d’exécution d’une requête (et pourquoi c’est crucial) ```markdown SELECT ... FROM ... JOIN ... WHERE ... GROUP BY ... HAVING ... WINDOW ... ORDER BY ... LIMIT/OFFSET ... ``` Mais le moteur raisonne autrement (ordre logique simplifié) : - FROM (inclut les sous-requêtes/CTE matérialisées logiquement) - ON (application des conditions de jointure) - Type de JOIN (INNER/LEFT/RIGHT/FULL) pour conserver/éliminer des lignes - WHERE (filtre sur le résultat après JOIN ; élimine des lignes) - GROUP BY (agrégation des lignes restantes) - HAVING (filtre après agrégation) - SELECT (projection : on calcule les expressions à afficher) - DISTINCT (si présent, dédoublonne) - ORDER BY - LIMIT/OFFSET (ou FETCH FIRST) Conséquence pratique : Rappel : ```markdown SELECT COUNT(*) AS nb_singers_users FROM Singer AS S WHERE nb_singers_users>4; ``` Un filtre mis dans WHERE ne voit pas l'alias « nb_singers_users » et ne peut pas utiliser d’alias calculés dans SELECT. 2) JOIN ... ON : bien plus qu’une clé étrangère Le JOIN ... ON n’est pas « réservé » aux correspondances id = id. C’est un prédicat de fusion de deux ensembles. - Jointure non-équijoin (ex. par intervalle) Associer une note à une tranche de notes : ```markdown SELECT s.name, s.marks, g.grade FROM Students s JOIN Grades g ON s.marks BETWEEN g.min_mark AND g.max_mark; ``` Ici, pas de FK (clé étrangère) ; c’est une condition logique. - Jointure par proximité (géospatiale, temporelle, fuzzy) * Géospatial (PostGIS) : ST_DWithin(a.geom, b.geom, 1000) * Temporel (plus proche horodatage) : ABS(a.ts - b.ts) < INTERVAL '5 minutes' - Jointure « tout accepter » (cartésienne contrôlée) ```markdown SELECT * FROM A JOIN B ON 1=1 ``` Équivalent à CROSS JOIN (produit cartésien). À manier avec précaution : explosion combinatoire. - Où placer les filtres ? ON vs WHERE ==INNER JOIN : un filtre sur la table de droite dans ON ou dans WHERE donne le même résultat (pas le même plan dans certains cas, mais résultat identique). ==LEFT JOIN : grosse différence ===Dans ON, le filtre n’élimine pas la ligne de gauche ; il affecte seulement quelles lignes de droite matchent (sinon NULL). ===Dans WHERE, un filtre sur une colonne de droite peut éliminer la ligne entière (effet « innerisation » du LEFT). Exemple piège : ```markdown -- ❌ Se comporte comme un INNER JOIN (les lignes sans B disparaissent) SELECT A.id, B.val FROM A LEFT JOIN B ON A.id = B.a_id WHERE B.val > 10; -- ✅ Conserve A sans B, mais ne garde que B.val>10 quand présent SELECT A.id, B.val FROM A LEFT JOIN B ON A.id = B.a_id AND B.val > 10; ``` Règle d’or : pour un LEFT JOIN, placez dans ON les conditions qui portent sur la table optionnelle (droite). 3) GROUP BY : pourquoi l’erreur, et la règle simple à suivre Erreur classique : ```markdown SELECT region, COUNT(*) AS n, price -- ❌ 'price' ni agrégé ni groupé FROM sales GROUP BY region; ``` Règle standard : toute expression présente dans SELECT (ou ORDER BY) doit être : #soit agrégée (MIN, MAX, SUM, AVG, COUNT, …), #soit dans le GROUP BY, #soit fonction de clés groupées ou déduite par une fonction déterministe de valeurs groupées (selon le moteur). Certains moteurs (MySQL sans ONLY_FULL_GROUP_BY) « tolèrent » mais le résultat est non déterministe. Activez ONLY_FULL_GROUP_BY / suivez le standard. Corrections possibles : ```markdown -- 1) Ajouter price au groupement (change la granularité) SELECT region, price, COUNT(*) FROM sales GROUP BY region, price; -- 2) Agréger price SELECT region, AVG(price) AS avg_price, COUNT(*) AS n FROM sales GROUP BY region; -- 3) Choisir une valeur arbitraire mais explicite (MySQL) SELECT region, ANY_VALUE(price) AS any_price, COUNT(*) AS n FROM sales GROUP BY region; ``` SQL n’est pas « une suite de mots-clés » : c’est un langage déclaratif avec un ordre logique d’exécution. En pensant comme le moteur, vous écrirez des requêtes plus justes, plus lisibles et plus performantes.

Commentaires

Aucun commentaire pour le moment. Soyez le premier Ă  commenter !

Pour laisser un commentaire, veuillez vous connecter ou créer un compte.