Mysql
 sql >> Base de données >  >> RDS >> Mysql

MySQL - compte par mois (y compris les enregistrements manquants)

Vous devez générer toutes les dates souhaitées, puis joindre vos données aux dates. Notez également qu'il est important de mettre des prédicats dans le ON de la jointure gauche clause, et d'autres dans le WHERE clause :

SELECT
  CONCAT(y, '-', LPAD(m, 2, '0')) as byMonth,
  COUNT(`created`) AS Total 
FROM (
  SELECT year(now())     AS y UNION ALL
  SELECT year(now()) - 1 AS y 
) `years`
CROSS JOIN (
  SELECT  1 AS m UNION ALL
  SELECT  2 AS m UNION ALL
  SELECT  3 AS m UNION ALL
  SELECT  4 AS m UNION ALL
  SELECT  5 AS m UNION ALL
  SELECT  6 AS m UNION ALL
  SELECT  7 AS m UNION ALL
  SELECT  8 AS m UNION ALL
  SELECT  9 AS m UNION ALL
  SELECT 10 AS m UNION ALL
  SELECT 11 AS m UNION ALL
  SELECT 12 AS m
) `months`
LEFT JOIN `qualitaet` q
ON YEAR(`created`) = y 
  AND MONTH(`created`) = m
  AND `status` = 1
WHERE STR_TO_DATE(CONCAT(y, '-', m, '-01'), '%Y-%m-%d') 
    >= MAKEDATE(year(now()-interval 1 year),1) + interval 5 month
  AND STR_TO_DATE(CONCAT(y, '-', m, '-01'), '%Y-%m-%d') 
    <= now()
GROUP BY y, m
ORDER BY y, m

Comment fonctionne ce qui précède ?

  • CROSS JOIN crée un produit cartésien entre toutes les années disponibles et tous les mois disponibles. C'est ce que vous voulez, vous voulez toutes les combinaisons année-mois sans interruption.
  • LEFT JOIN ajoute tous les qualitaet enregistrements au résultat (s'ils existent) et les joint au produit cartésien année-mois d'avant. Il est important de mettre des prédiactes comme le status = 1 prédicat ici.
  • COUNT(created) ne compte que les valeurs non NULL de created , c'est-à-dire lorsque le LEFT JOIN ne produit aucune ligne pour une année-mois donnée, nous voulons 0 par conséquent, pas 1 , c'est-à-dire que nous ne voulons pas compter le NULL valeur.

Remarque sur les performances

Ce qui précède fait un usage intensif des opérations de chaîne et de l'arithmétique date-heure dans votre ON et WHERE prédicats. Cela ne fonctionnera pas pour beaucoup de données. Dans ce cas, mieux vaut pré-tronquer et indexer vos années-mois dans le qualitaet table et n'opèrent que sur ces valeurs.