首先让我说,我认为这更像是在您的演示逻辑(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