1

我有一些包含数据的表,我正在尝试生成如下格式的数据透视表:

面积 | 类型 | 2013-08-25 | 2013-08-26 | 2013-08-27等..
南 | 红色 | 5 | 2 | 9
北 | 蓝色 | 3 | 0 | 7

目前为了生成这个,我使用 PHP 循环遍历每个日期并根据给定的开始和结束日期为每个日期生成 sum(if 语句。

我知道我可以在之前运行查询并按日期分组,然后在 PHP 中组装它,但 SQL 解决方案似乎比这更容易。

这是完成我想做的事情的最佳方式,还是我错过了另一种更简单的方式?

示例查询:

SELECT 
iw.display_name as Area, 
iet.type as 'Type', 
sum(if(date(iac.created_at) = '2013-08-25',1,0)) as '2013-08-25', 
sum(if(date(iac.created_at) = '2013-08-26',1,0)) as '2013-08-26', 
sum(if(date(iac.created_at) = '2013-08-27',1,0)) as '2013-08-27', 
sum(if(date(iac.created_at) = '2013-08-28',1,0)) as '2013-08-28', 
sum(if(date(iac.created_at) = '2013-08-29',1,0)) as '2013-08-29', 
sum(if(date(iac.created_at) = '2013-08-30',1,0)) as '2013-08-30', 
sum(if(date(iac.created_at) = '2013-08-31',1,0)) as '2013-08-31',  
count(iac.id) as total 
FROM iac
JOIN ioc on ioc.id = iac.ioc_id
JOIN iet on iet.id = ioc.iet_id
JOIN iw  on  iw.id = iac.iw_id
WHERE date(iac.created_at) between '2013-08-25' and '2013-08-31'
GROUP BY iw.id, iet.id
ORDER BY iw.display_name, iet.type
4

2 回答 2

1

你的方法很好。if您可以通过删除条件来简化它(因为您使用的是 MySQL) 。布尔值被视为1真假0

SELECT iw.display_name as Area, iet.type as `Type`, 
       sum(date(iac.created_at) = '2013-08-25') as `2013-08-25`, 
       sum(date(iac.created_at) = '2013-08-26') as `2013-08-26`, 
       sum(date(iac.created_at) = '2013-08-27') as `2013-08-27`, 
       sum(date(iac.created_at) = '2013-08-28') as `2013-08-28`, 
       sum(date(iac.created_at) = '2013-08-29') as `2013-08-29`, 
       sum(date(iac.created_at) = '2013-08-30') as `2013-08-30`, 
       sum(date(iac.created_at) = '2013-08-31') as `2013-08-31`,  
       count(iac.id) as total 
FROM iac
JOIN ioc on ioc.id = iac.ioc_id
JOIN iet on iet.id = ioc.iet_id
JOIN iw  on  iw.id = iac.iw_id
WHERE iac.created_at >= date('2013-08-25') and iac.created_at < date('2013-09-01')
GROUP BY iw.id, iet.id
ORDER BY iw.display_name, iet.type;

我还将列别名中的单引号替换为反引号。您应该只对字符串常量使用单引号。

我还用不等式替换了日期逻辑。这将删除列周围的函数调用 ( date()),从而更有可能将索引用于此过滤。

于 2013-08-29T01:37:58.377 回答
1

就旋转而言,这与您在 MySql 中获得的一样好。您可以通过使用动态 SQL 实现此查询并将其包装到这样的存储过程中来为自己简化事情(以免每次都键入所有可能的日期)

DELIMITER $$
CREATE PROCEDURE sp_report(IN dt_start DATE, IN dt_end DATE)
BEGIN
  SET @sql = NULL;

  SELECT GROUP_CONCAT(DISTINCT
           CONCAT('SUM(CASE WHEN DATE(iac.created_at) = ''',
           DATE_FORMAT(created_at, '%Y-%m-%d'),
           ''' THEN 1 ELSE 0 END) `',
           DATE_FORMAT(created_at, '%Y-%m-%d'), '`'))
    INTO @sql
    FROM iac
   WHERE iac.created_at >= DATE_FORMAT(dt_start, '%Y-%m-%d 00:00:00') 
     AND iac.created_at <= DATE_FORMAT(dt_end,   '%Y-%m-%d 23:59:59') ;

  SET @sql = CONCAT('SELECT iw.display_name area, iet.type `type`, ', @sql, 
                    ', COUNT(iac.id) total 
                       FROM iac JOIN ioc 
                         ON ioc.id = iac.ioc_id JOIN iet 
                         ON iet.id = ioc.iet_id JOIN iw  
                         ON iw.id  = iac.iw_id
                      WHERE iac.created_at >= ', DATE_FORMAT(dt_start, '%Y-%m-%d 00:00:00'),  
                    '   AND iac.created_at <= ', DATE_FORMAT(dt_end,   '%Y-%m-%d 23:59:59'),
                    ' GROUP BY iw.id, iet.id
                      ORDER BY iw.display_name, iet.type');
  PREPARE stmt FROM @sql;
  EXECUTE stmt;
  DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

示例用法:

CALL sp_report('2013-08-25', '2013-08-31');
于 2013-08-29T02:07:51.553 回答