【问题标题】:Grouping records hour by hour or day by day and filling gaps with zero or null in mysql按小时或按天对记录进行分组,并在 mysql 中用零或空填充空白
【发布时间】:2012-07-01 17:25:16
【问题描述】:

我写了一个查询,每小时计算记录数:

select TO_CHAR(copied_timestamp, 'YYYY-MM-DD HH24'),count(*) from req group by
TO_CHAR(copied_timestamp, 'YYYY-MM-DD HH24');

结果是:

2012-02-22 13    2280
2012-02-22 15    1250
2012-02-22 16    1245
2012-02-22 19    1258

但我需要这样的结果:

2012-02-22 13    2280
2012-02-22 14    0
2012-02-22 15    1250
2012-02-22 16    1245
2012-02-22 17    0
2012-02-22 18    0
2012-02-22 19    1258

我也有这些按天和月分组的查询!

select TO_CHAR(copied_timestamp, 'YYYY-MM-DD'),count(*)  from req
group by TO_CHAR(copied_timestamp, 'YYYY-MM-DD');

select TO_CHAR(copied_timestamp, 'YYYY-MM'),count(*)  from req
group by TO_CHAR(copied_timestamp, 'YYYY-MM');

我也需要用零或空来填充它们的空白。 非常感谢任何帮助。

注意: 使用CONNECT BY 在oracle 中有这个问题的答案,但我需要在Mysql 中得到答案,因为Mysql 不支持CONNECT BYHere is the link

【问题讨论】:

  • 该表是否每天有 24 记录,代表一天中的每个小时?
  • 实际上没有,它可以有更多的记录。每秒可能有 5 条或更多条记录!
  • 引用问题中CONNECT BYLEVEL 的唯一目的是生成行。它是 Oracle 中的一个成语,在 Mysql 中应该有一个等效项,它做同样的事情。也许这会有所帮助:stackoverflow.com/questions/1806484/…
  • 我看到了你的参考。但我无法生成带有日期的行,作为他们的数据!如果我可以使用您链接中提到的方法生成日期范围,我想我可以处理。
  • 如果你在 MySQL 中需要答案,为什么还要坚持oracle 标签? (你把它取下来后放回去。)

标签: mysql sql oracle group-by hour


【解决方案1】:

我创建了一个名为 TBL_NUMBERS 的表

CREATE TABLE `TBL_NUMBER` (`n` int(11) NOT NULL)

并插入从 1 到 1000 的记录。 现在我可以使用这个查询生成任何类型的日期范围:

SELECT '2012-06-21' + INTERVAL n-1 [DAY | HOUR | MINUTE] or as dateRange
 FROM TBL_NUMBER
WHERE '2012-06-21' + INTERVAL n-1 [DAY | HOUR | MINUTE] <= '2012-06-23';

然后我可以将我的结果加入此表以填补日期空白。 如果我需要超过 1000 个日期范围,我可以在 TBL_NUMBER 中插入更多记录

如果你有更好的主意,我很想知道;)

【讨论】:

    【解决方案2】:

    生成一个单列 dates_hours 表,其中包含合理范围内的所有日期和时间(例如,从 1900 到 2200)。 然后从这个表中对您当前的查询执行LEFT JOIN

    为了使这项技术正确执行,您可能需要在表中添加一个索引列,其中包含转换后的时间戳(您的copied_timestamp 转换为DATETIME,四舍五入到小时)

    SELECT date_hour, count(req.converted_timestamp)
    FROM
        dates_hours 
        LEFT JOIN req ON req.converted_timestamp = dates_hours.date_hour
    WHERE date_hour
        BETWEEN (SELECT MIN(req.converted_timestamp) FROM req)
        AND (SELECT MAX(req.converted_timestamp) FROM req)
    GROUP BY date_hour
    

    要生成dates_hours 表:

    CREATE TABLE dates_hours (date_hour DATETIME PRIMARY KEY);
    
    DELIMITER $$$
    CREATE PROCEDURE generate_dates_hours (to_date DATETIME)
    BEGIN
    
        DECLARE start_date DATETIME;
        DECLARE inc INT;
    
        SELECT MAX(date_hour) INTO start_date FROM dates_hours;
        IF start_date IS NULL THEN
            SET start_date = '1900-01-01';
        END IF;
        SET inc = 1;
        WHILE start_date + INTERVAL inc HOUR  <= to_date DO
            INSERT INTO dates_hours VALUE (start_date + INTERVAL inc HOUR);
            SET inc = inc +1;
        END WHILE;
    
    END $$$
    DELIMITER ;
    
    CALL generate_dates_hours('2200-01-01');
    

    好的,现在我正在校对自己,我意识到这是一个非常牵强的解决方案。我希望有人想出一个更优雅的。

    【讨论】:

    • 谢谢牦牛。这解决了问题,但对于我的用例来说,维护代码有点困难。我找到了另一个解决方案并将其发布在这里。渴望知道你的想法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多