GROUP BY MONTH()隐藏结果

时间:2012-09-26 07:59:30

标签: mysql group-by

我正在计算每个月有多少结果。

这是我的疑问:

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配置的问题吗?

很多

2 个答案:

答案 0 :(得分: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而不是':'的原因是否有原因?)


你也可以使用其他一些DATE and TIME functions的MySQL,这样每行调用的函数就更少了,可能是一个更有效的查询:

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 ;

答案 1 :(得分:2)

您还必须GROUP BY年份:

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

您的原始查询在任何聚合函数之外的YEAR(t.date)子句中使用SELECT而不进行分组 - 因此,您可以获得12个组(每个可能的月份一个)组(可能包含多年的日期)a&#34;随机&#34; mySql选择year作为选择。严格地说,这是没有意义的,并且永远不应该允许执行查询。但MySql ... 叹息