1

我试图计算每个月有多少结果。

这是我的查询:

SELECT 
    COUNT(*) as nb,
    CONCAT(MONTH(t.date),0x3a,YEAR(t.date)) as period
FROM table1 t
WHERE t.criteria = 'value'
GROUP BY MONTH(t.date)
ORDER BY YEAR(t.date)

我的结果:

nb  period
---------------
7   6:2009
46  8:2009
2   10:2009
1   11:2009
14  1:2009
9   9:2010
161 7:2010
5   2:2010
88  3:2010
28  4:2010
4   5:2011
2   12:2011

问题是,我确定我的结果介于 5:2011 和 12:2011 之间,以及自 2009 年以来的其他时期......:/

这是我的请求还是mysql配置的问题?

多谢

4

2 回答 2

3

您必须按年和月分组。否则,您 2012 年 4 月的行也将与 2011 年 4 月(和 2010 年 4 月 ...)行分组。

SELECT 
    COUNT(*) AS nb,
    CONCAT(MONTH(t.date), ':', YEAR(t.date)) AS period
FROM table1 AS t
WHERE t.criteria = 'value'
GROUP BY YEAR(t.date)
       , MONTH(t.date) ;

0x3a(你使用而不是有理由':'吗?)


您还可以使用 MySQL 的其他一些DATE 和 TIME 函数,因此每行调用的函数更少,并且可能是更有效的查询:

SELECT 
    COUNT(*) AS nb,
    DATE_FORMAT(t.date, '%m:%Y') AS period
FROM table1 AS t
WHERE t.criteria = 'value'
GROUP BY EXTRACT( YEAR_MONTH FROM t.date) ;

对于多个查询,在数据库中有一个永久的日历表(包含所有日期或所有年月)或什至几个日历表很有用。例子:

CREATE TABLE CalendarYear
  ( Year SMALLINT UNSIGNED NOT NULL
  , PRIMARY KEY (Year)
  ) ENGINE = InnoDB ;

INSERT INTO CalendarYear
  (Year)
VALUES
  (1900), (1901), ..., (2099) ;

CREATE TABLE CalendarMonth
  ( Month TINYINT UNSIGNED NOT NULL
  , PRIMARY KEY (Month)
  ) ENGINE = InnoDB ;

INSERT INTO CalendarMonth
  (Month)
VALUES
  (1), (2), ..., (12) ;

这些也可以帮助我们制作我们需要的:

CREATE TABLE CalendarYearMonth
  ( Year SMALLINT UNSIGNED NOT NULL
  , Month TINYINT UNSIGNED NOT NULL
  , FirstDay DATE NOT NULL
  , NextMonth_FirstDay DATE NOT NULL
  , PRIMARY KEY (Year, Month)
  ) ENGINE = InnoDB ;

INSERT INTO CalendarYearMonth
  (Year, Month, FirstDay, NextMonth_FirstDay)
SELECT
    y.Year
  , m.Month
  , MAKEDATE(y.Year, 1) + INTERVAL (m.Month-1) MONTH
  , MAKEDATE(y.Year, 1) + INTERVAL (m.Month) MONTH
FROM
    CalendarYear AS y
  CROSS JOIN
    CalendarMonth AS m ;

然后,您可以使用日历表编写更复杂的查询,例如您想要的变化(缺少月份)并且可能更有效。在SQL-Fiddle中测试:

SELECT 
    COUNT(t.date) AS nb,
    CONCAT(cal.Month, ':', cal.Year) AS period
FROM
        CalendarYearMonth AS cal
    JOIN
        ( SELECT
              YEAR(MIN(date))  AS min_year
            , MONTH(MIN(date)) AS min_month
            , YEAR(MAX(date))  AS max_year
            , MONTH(MAX(date)) AS max_month
          FROM table1
          WHERE criteria = 'value'
        ) AS mm
      ON  (cal.Year, cal.Month) >= (mm.min_year, mm.min_month)
      AND (cal.Year, cal.Month) <= (mm.max_year, mm.max_month)
    LEFT JOIN
        table1 AS t
      ON  t.criteria = 'value'
      AND t.date >= cal.FirstDay
      AND t.date < cal.NextMonth_FirstDay
GROUP BY 
    cal.Year, cal.Month ;
于 2012-09-26T08:02:57.400 回答
2

您还必须GROUP BY在年份:

GROUP BY MONTH(t.date), YEAR(t.date)

您的原始查询在任何聚合函数之外YEAR(t.date)SELECT子句中使用,而不按它进行分组——因此,您得到正好 12 个组(每个可能的月份一个),并且对于每个组(可能包含多年的日期)一个“随机" 年份由 MySql 选择进行选择。严格来说,这是没有意义的,查询不应该被允许执行。但是 MySql...叹息

于 2012-09-26T08:01:53.807 回答