微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sql – 在Rails Postgres中以任意时间间隔计算记录的最佳方式

我的应用程序有一个带有时间戳事件的Events表.

我需要在最近的N个时间间隔内报告事件计数.对于不同的报告,间隔可以是“每周”或“每一天”或“每小时”或“每15分钟间隔”.

例如,用户可以显示他们每周,每天或每小时或四分之一小时收到的订单数量.

1)我的偏好是动态地做一个单一的SQL查询(我正在使用Postgres)按任意时间间隔进行分组.有办法吗?

2)一个简单但丑的强力方式是对按时间戳排序的开始/结束时间范围内的所有记录执行单个查询,然后通过任意间隔手动构建一个计数.

3)另一种方法是将每个间隔的事件表添加单独的字段,并静态存储the_week the_day,the_hour和the_quarter_hour字段,以便在创建记录时(一次)而不是每次我关于该领域的报告.

这里最好的做法是,如果需要,我可以修改模型和预先存储间隔数据(尽管以适度的费用将表格宽度加倍)?

解决方法

幸运的是,你正在使用Postgresql. generate_series()(Postgres具体),window function lead()和LEFT JOIN是你的朋友:

测试用例

给定以下测试表(您应该提供):

CREATE TEMP TABLE event(event_id serial,ts timestamp);
INSERT INTO event (ts)
SELECT generate_series('2015-04-17 0:0'::timestamp,'2015-04-20 0:0'::timestamp,interval '7 min') + random() * interval '7 min';

每7分钟一次(0到7分钟随机).

基本解决方

查询对任意时间间隔的事件进行计数. 17分钟的例子:

WITH grid AS (
   SELECT start_time,lead(start_time) OVER (ORDER BY start_time) AS end_time
   FROM  (
      SELECT generate_series(min(ts),max(ts),interval '17 min') AS start_time
      FROM   event
      ) x
   )
SELECT start_time,count(e.ts) AS events
FROM   grid       g
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.end_time
GROUP  BY 1
ORDER  BY 1;

>查询从基表自动收集最小和最大时间戳以涵盖表的完整时间范围.
您可以改为使用任意时间范围.
>输入您选择的间隔时间.可以任何时间间隔你可以想到.
>结果中每个时间间隔的一行.如果没有事件发生,你会得到0的计数.
>确保正确处理上下边框:
PostgreSQL Error on Heroku with “BETWEEN”
>对于时间范围内的运行计数,请参阅此相关答案:
PostgreSQL: running count of rows for a query ‘by minute’

“过去一周每15分钟”一例

基本格式与to_char().

WITH grid AS (
   SELECT start_time,lead(start_time) OVER (ORDER BY start_time) AS end_time
   FROM   generate_series(Now()::date - 7  -- truncates to start of day,Now(),interval '15 min') AS start_time
   )
SELECT to_char(start_time,'YYYY-MM-DD HH24:MI'),count(e.ts) AS events
FROM   grid       g
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.end_time
GROUP  BY start_time
ORDER  BY start_time;

角箱最后一排

要舍弃它,你可以使用:

lead(start_time,1,Now()) OVER (ORDER BY start_time) AS end_time

..其中Now()是您的示例的时间范围的上边界.否则最后一个间隔将被截断,因为上边框为NULL.

当没有前导行存在时,lead()经常被忽略,提供认的功能.

一般解决方案覆盖角箱

WITH vals AS (
   SELECT Now()::date - 7   AS frame_start  -- enter values once,Now()             AS frame_end,interval '15 min' AS t_interval
   ),grid AS (
   SELECT start_time,lead(start_time,frame_end) OVER (ORDER BY start_time) AS end_time
   FROM   (
      SELECT generate_series(frame_start,frame_end,t_interval) AS start_time,frame_end
      FROM vals
      ) x
   )
SELECT to_char(start_time,count(e.ts) AS events
FROM   grid       g
LEFT   JOIN event e ON e.ts >= g.start_time
                   AND e.ts <  g.end_time
GROUP  BY start_time
ORDER  BY start_time;

SQL Fiddle显示全部.

原文地址:https://www.jb51.cc/mssql/82001.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐