我有一些包含数据的表,我正在尝试按以下格式生成类似于表的数据集:
Area | Type | 2013-08-25 | 2013-08-26 | 2013-08-27, etc.. South | Red | 5 | 2 | 9 North | Blue | 3 | 0 | 7
目前为了生成这个,我使用PHP遍历每个日期并生成总和(如果每个日期的语句基于给定的开始和结束日期。
我知道我可以先运行查询并按日期分组,然后在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
答案 0 :(得分:1)
你的方法很好。您可以通过删除if
条件来简化它(因为您使用的是MySQL)。对于true,布尔值被视为1
,对于false,被视为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()
),使得更有可能将索引用于此过滤。
答案 1 :(得分: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');