0

基本上,我有一个 mysql 数据库表,其中包含一个日期时间列和一个类别列。我想创建一个 SQL 查询来检索类别列中存在的所有值,并计算按日期时间列的月/年分组的每个类别值的出现次数。如果可能的话,我也希望返回总数。一个月内发生的所有事件的总数和计数的类别总数。

注意:类别值不能硬编码,因为它们由用户设置并存储在另一个表中。

DB表具有以下结构:

datetime    |  category

2009-01-05  |  fish
2009-01-06  |  fish
2009-01-06  |  potato
2009-01-16  |  fish
2009-02-08  |  pineapple
2009-02-15  |  potato

我希望查询返回的结果是:

Month    |  fish  |  potato  |  pineapple   |  total

2009-01  |   3    |   1      |   0          |    4
2009-02  |   0    |   1      |   1          |    2

Total    |   3    |   2      |   1          |    6

我认为(希望)它可以在单个 SQL 查询中完成,但我不知道如何。谁能帮我?

谢谢!

4

2 回答 2

2

首先让我说,我认为这更像是在您的演示逻辑(php 代码)中处理的问题。但是,SQL 可以产生这样的结果。您正在尝试完成两件不同的事情。

首先,您正在寻找一张PIVOT桌子。MySQL 不支持该PIVOT命令,但您可以使用MAX和来模拟它CASE。当您知道潜在类别的数量时,这很有效,但不适用于您的情况。

接下来,您想要有行总计,然后是最终总计行。 同样,这更适合在表示层中处理。

但是,使用Dynamic SQL,您可以同时实现PIVOT表和行总计。这是一些示例代码:

首先构建您的 PIVOT 变量@sql:

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'COUNT(IF(category = ''', category, ''',1,NULL)) AS ', category)
  ) INTO @sql
FROM (
    SELECT *, 
      @rn:=IF(@prevMonthYear=CONCAT(YEAR(datetime),'-',MONTH(datetime)),@rn+1,1) rn,
      @prevMonthYear:=CONCAT(YEAR(datetime),'-',MONTH(datetime)) dt
    FROM yourtable JOIN (SELECT @rn:=0,@prevParent:=0) t
) t
;

现在构建您的行摘要变量@totsql:

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'SUM(', category, ') AS sum_', category)
  ) INTO @totsql
FROM (
    SELECT *, 
      @rn:=IF(@prevMonthYear=CONCAT(YEAR(datetime),'-',MONTH(datetime)),@rn+1,1) rn,
      @prevMonthYear:=CONCAT(YEAR(datetime),'-',MONTH(datetime)) dt
    FROM yourtable JOIN (SELECT @rn:=0,@prevParent:=0) t
) t
;

把它们放在一起:

SET @sql = CONCAT('SELECT dt,
                          ', @sql, ', COUNT(1) total
                  FROM (
                  SELECT *, 
                        @rn:=IF(@prevMonthYear=CONCAT(YEAR(datetime),''-'',MONTH(datetime)),@rn+1,1) rn,
                        @prevMonthYear:=CONCAT(YEAR(datetime),''-'',MONTH(datetime)) dt
                      FROM yourtable JOIN (SELECT @rn:=0,@prevParent:=0) t
                  ) t
                  GROUP BY dt

                  UNION 
                  SELECT ''Totals'',', @totsql, ', SUM(total)  
                  FROM (

                    SELECT dt,
                            ', @sql, ', COUNT(1) total
                    FROM (
                    SELECT *, 
                          @rn:=IF(@prevMonthYear=CONCAT(YEAR(datetime),''-'',MONTH(datetime)),@rn+1,1) rn,
                          @prevMonthYear:=CONCAT(YEAR(datetime),''-'',MONTH(datetime)) dt
                        FROM yourtable JOIN (SELECT @rn:=0,@prevParent:=0) t
                    ) t
                    GROUP BY dt

                  ) t2
                  ;');

PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

结果:

MONTH       FISH   POTATO   PINEAPPLE   TOTAL
2009-1      3      1        0           4
2009-2      0      1        1           2
Totals      3      2        1           6
于 2013-05-31T02:57:17.393 回答
0

您可以有多个嵌套查询,也可以在这种情况下使用 mysql 循环。最简单的事情是获取您需要的所有数据并使用 php 处理它。

于 2013-05-31T03:18:08.107 回答