2014-01-21 55 views
1

我有一个postgresql 9.1表,其中包含开始和结束时间戳,记录用户标识可能重叠的时间段。例如:如何计算postgresql中多个记录的开始和结束时间戳之间的总时间

Userid Begin      End 
1  2014-01-19 21:14:59+00 2014-01-19 21:30:00+00 
2  2014-01-19 21:19:29+00 2014-01-19 21:40:30+00 
1  2014-01-19 21:16:29+00 2014-01-19 21:31:30+00 
3  2014-01-19 21:15:22+00 2014-01-19 21:30:29+00 
2  2014-01-19 21:29:59+00 2014-01-19 21:45:00+00 
3  2014-01-19 21:15:25+00 2014-01-19 21:35:10+00 
4  2014-01-19 22:00:01+00 2014-01-19 22:05:20+00 

我需要得到每个用户ID的所有分的总和在这些行确保时间不被重复计算的个人用户标识,从而使输出将是:

Userid Hour  Total Minutes 
1  21  n 
2  21  n 
3  21  n 
4  22  n 
+0

使用'tzrange'的'+'(范围联合)运算符对此会很有趣。很遗憾,它不支持不连续性;这让我停止玩它变得更加困难。 –

回答

1

这是一个难题,但至少Postgres具有lag()的功能。

这是想法。假设你有重叠。找到没有重叠的第一个元素。给它一个1的标志值。然后做一个这个值的累计和。结果是,不同的时间段现在根据它们的“岛屿”被分配值。然后简单的聚合工作。

下面将在许多情况下工作,使用lag()

select userid, sum(secs)/60 as minutes 
from (select userid, Island, min(begin) as begin, max(end) as end, 
      extract(epoch from max(end) - min(begin)) as secs 
     from (select t.*, 
        sum(IslandBegin) over (partition by userid order by begin) as Island 
      from (select t.*, 
         (case when lag(end) over (partition by userid order by begin) >= begin 
           then 0 
           else 1 
          end) as IslandBegin 
        from table t 
       ) t 
      ) t 
     group by userid, Island 
    ) t 
group by userid; 

注意end是一个保留字,所以相应地调整代码。

以上并不总是有效。它假定重叠是与之前的开始相同的,可能并非如此。考虑{(1,100),(2,5),(8,10)}。我认为正确的逻辑仍然需要相关的子查询。最里面的查询需要从改变:

  from (select t.*, 
         (case when lag(end) over (partition by userid order by begin) >= begin 
           then 0 
           else 1 
          end) as IslandBegin 
        from table t 
       ) t 

到:

  from (select t.*, 
         coalesce((select 1 
            from table t2 
            where t2.end >= t.begin and 
             t2.begin < t.begin 
            limit 1 
           ), 0 
           ) as IslandBegin 
        from table t 
       ) t 

其实,这是没有那么糟糕,我了解到,lag()不能用于所有这样的情况。

+0

在将表名更改为活动表后,在尝试此代码时,它返回列(15)“isbegin”不存在。我将它改为IslandBegin并重新开始。它回来了:'一个子查询返回多个行作为表达式' – Steve

+0

@Steve。 。 。那应该是'IslandBegin'。 –

+0

将'tzrange'和它的'+'运算符合并到这里可能会很有趣。 –

相关问题