Si vous avez réalisé des requêtes de reporting pour extraire des statistiques à partir de grosses tables, vous avez dû souvent vous y prendre en plusieurs requêtes pour arriver à constituer l'ensemble de vos statistiques, ce qui peut vite devenir pénible.
Imaginons les 2 tables suivantes :
- news avec un statut published enum ('true','false) et une FK vers category
- category
Si vous souhaitez obtenir le nombre total de news dans chaque category, naturellement le group by va vous venir en aide :
SELECT ||t||n.category_id, ||t||COUNT(*) AS total_news FROM ||t||news n ||t||LEFT JOIN category c ON n.category_id = c.category_id GROUP BY ||t||n.category_id ORDER BY ||t||total_news DESC
Ce qui va vous donner l'ensemble des category ainsi que le nombre de news dans chacune de ces category.
Sauf que c'est là que cela se corse, vous aimeriez bien savoir en même temps, parmi ces news de toutes ces category, combien de news sont publiées vs sont non publiées.
Instinctivement, vous voudriez ajouter des count() avec des where, sauf que MySQL ne permet pas de mettre des clauses dans la fonction count(), seulement au niveau du where, dans lequel vous ne pourrez pas grouper sur plusieurs clauses.
Vous allez vous résoudre à le faire en plusieurs requêtes et c'est là que nous intervenons en vous proposant cette solution alternative :
SELECT ||t||n.category_id, ||t||COUNT(*) AS total_news, ||t||SUM(IF(n.news_published = 'true', 1, 0)) AS total_news_published, ||t||SUM(IF(n.news_published = 'false', 1, 0)) AS total_news_not_published FROM ||t||news n ||t||LEFT JOIN category c ON n.category_id = c.category_id GROUP BY ||t||n.category_id ORDER BY ||t||total_news DESC
La solution consiste à transformer notre count where utopique en une somme conditionnelle où nous influons directement sur la somme en effectuant notre test dedans et en forcant le +0 ou le +1.
Le résultat est donc bien conforme à ce que nous souhaitions :
Pratique non ?