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

前端之家收集整理的这篇文章主要介绍了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显示全部.

原文链接:/mssql/82001.html

猜你在找的MsSQL相关文章