如何按SQL中行之间的列的差异进行分组?

时间:2013-08-13 02:37:59

标签: sql ruby postgresql

我有一张带有created_at时间戳的事件表。我想将它们分成N秒相隔的事件组,特别是130秒。然后,对于每个组,我只需要知道最低时间戳和最高时间戳。

以下是一些示例数据(忽略时间戳的格式,它是日期时间字段):

------------------------
| id | created_at      |
------------------------
| 1  | 2013-1-20-08:00 |
| 2  | 2013-1-20-08:01 |
| 3  | 2013-1-20-08:05 |
| 4  | 2013-1-20-08:07 |
| 5  | 2013-1-20-08:09 |
| 6  | 2013-1-20-08:12 |
| 7  | 2013-1-20-08:20 |
------------------------

我希望得到的结果是:

-------------------------------------
| started_at      | ended_at        |
-------------------------------------
| 2013-1-20-08:00 | 2013-1-20-08:01 |
| 2013-1-20-08:05 | 2013-1-20-08:09 |
| 2013-1-20-08:12 | 2013-1-20-08:12 |
| 2013-1-20-08:20 | 2013-1-20-08:20 |
-------------------------------------

我用Google搜索并搜索了一些可能的方法来表达这个问题并进行了一段时间的实验,但我无法弄明白。我已经可以在Ruby中执行此操作,我只想弄清楚是否可以将其移至数据库级别。如果你很好奇或者更容易想象,这就是Ruby中的样子:

groups = SortedSet[*events].divide { |a,b| (a.created_at - b.created_at).abs <= 130 }
groups.map do |group|
  { started_at: group.to_a.first.created_at, ended_at: group.to_a.last.created_at }
end

有没有人知道如何在SQL中执行此操作,特别是PostgreSQL?

1 个答案:

答案 0 :(得分:2)

我认为您希望在与之前的差异大于130秒时启动每个新分组。您可以使用滞后和日期算法来确定分组的开始位置。然后做累积总和以获得分组:

select Grouping, min(created_at), max(created_at)
from (select t.*, sum(GroupStartFlag) over (order by created_at) as Grouping
      from (select t.*,
                   lag(created_at) over (order by created_at) as prevca,
                   (case when extract(epoch from created_at - lag(created_at) over (order by created_at)) < 130
                         then 0 else 1
                    end) as GroupStartFlag
            from t
           ) t
     ) t
group by Grouping;

最后一步是通过“分组”标识符汇总以获取最早和最晚的日期。