MySQL - count by month (including missing records)

后端 未结 1 2001
旧巷少年郎
旧巷少年郎 2020-12-11 23:14

I have this SELECT:

SELECT
  DATE_FORMAT(`created`, \'%Y-%m\') as byMonth,
  COUNT(*) AS Total 
FROM 
  `qualitaet`
WHERE
  `created` >= MAKEDATE(year(now         


        
相关标签:
1条回答
  • 2020-12-11 23:33

    You need to generate all the wanted dates, and then left join your data to the dates. Note also that it is important to put some predicates in the left join's ON clause, and others in the 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
    

    How does the above work?

    • CROSS JOIN creates a cartesian product between all available years and all available months. This is what you want, you want all year-month combinations with no gaps.
    • LEFT JOIN adds all the qualitaet records to the result (if they exist) and joins them to the year-month cartesian product from before. It is important to put prediactes like the status = 1 predicate here.
    • COUNT(created) counts only non-NULL values of created, i.e. when the LEFT JOIN produces no rows for any given year-month, we want 0 as a result, not 1, i.e. we don't want to count the NULL value.

    A note on performance

    The above makes heavy use of string operations and date time arithmetic in your ON and WHERE predicates. This isn't going to perform for lots of data. In that case, you should better pre-truncate and index your year-months in the qualitaet table, and operate only on those values.

    0 讨论(0)
提交回复
热议问题