基本上,我有一个mysql db表,它包含一个datetime列和一个category列。我想创建一个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查询中完成,但我无法弄清楚如何。 任何人都可以帮助我吗?
谢谢!
答案 0 :(得分: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
答案 1 :(得分:0)
您可以拥有多个嵌套查询,或者在这种情况下可以使用mysql循环。最简单的方法是获取所需的所有数据并使用php处理它。