MySQL GROUP BY和填充空行

时间:2011-08-31 04:08:52

标签: php mysql

我确信之前已经回答了这个问题,但我无法在细节中找到它。

对于分析系统,我需要能够对行进行分组并将其返回到图表上,按分钟,小时,日,月或年分组。我的工作正常(下面的示例代码)。

SELECT COUNT( DISTINCT user_id ) ,  `hour` ,  `timestamp` 
FROM tracking_request
WHERE site_id =  '3'
AND  `timestamp` <  '2011-08-31 04:05:45'
AND  `timestamp` >  '2011-08-29 22:00:00'
GROUP BY  `hour` ,  `day` ,  `month` ,  `year` 
ORDER BY  `timestamp` ASC

问题是,像大多数图表一样,我需要填补数据不存在的空白(例如,最后3分钟没有行)。我阅读了关于创建“日历表”并加入该数据的内容,但是我如何才能有效地为每个比例做到这一点(例如,年份将比分钟更容易,因为分钟需要表中的许多行)?如果它有帮助,表格中有一列(如上所示,你可以看到有“小时”,“天”等)。

修改

我最终使用PHP通过使用空数组然后填充它来实现这一点。如果有人能够想到一个全部(或大部分)SQL解决方案,那就更棒了。

2 个答案:

答案 0 :(得分:2)

在这个答案中,我将概述如何生成日历表。

为日,小时和分钟创建三个表:

CREATE TABLE days (
  day DATE,
  PRIMARY KEY (day)
) 
CREATE TABLE hours (
  hour INT,
  PRIMARY KEY (hour)
) 
CREATE TABLE minutes (
  minute INT,
  PRIMARY KEY (minute)
) 

使用0到23之间的数字填充小时表,使用0到59之间的数字填充分钟表。要填写日期表,您可以创建如下过程:

CREATE PROCEDURE make_days(IN start_date DATE, IN end_date DATE)
BEGIN
  DECLARE curr_date DATE;
  SET curr_date = start_date;
  WHILE curr_date <= end_date DO
    INSERT IGNORE INTO days(day)  VALUES(curr_date);
    SET curr_date = DATE_ADD(curr_date, INTERVAL 1 DAY);
  END WHILE;
END

然后,您可以调用此过程来创建如下日期:

CALL make_days('2011-01-01','2012-12-31');

现在,您可以使用类似于以下内容的查询为给定时间间隔内的每分钟创建值:

SELECT YEAR(day) AS year, MONTH(day) AS month, DAYOFMONTH(day) AS day, hour, minute
FROM days, hours, minutes
WHERE CAST(CONCAT(day,' ',hour,':',minute) AS DATETIME) BETWEEN '2011-08-31 22:00' AND '2011-09-01 10:00'
ORDER BY year, month, day, hour, minute

答案 1 :(得分:1)

这通常在数据仓库中通过具有包含所有可能日期的列表的日期维度来完成。您对日期维度执行OUTER JOIN,并将空值COALESCE为0。

相关问题