根据列值查找表中的时间段

时间:2012-03-20 16:51:12

标签: postgresql

我的postgreSQL 8.3.14数据库中有以下表格

     timestamp           status
2012-03-12 19:15:01        f
2012-03-12 19:15:02        f
2012-03-12 19:15:05        f
2012-03-12 19:17:01        t
-- END OF SLOT ONE (change from f to t)
2012-03-12 19:20:01        f
2012-03-12 19:25:01        f
2012-03-12 19:27:01        f
2012-03-12 20:15:01        t
-- END OF SLOT TWO (change from f to t)

不,我想得到以下结果:

  • 1号插槽(2012-03-12 19:17:01 - 2012-03-12 19:15:01)
  • 插槽2持续时间(2012-03-12 20:15:01 - 2012-03-12 19:20:01)

因此,每次状态值从f变为t时,都会开始一个新的插槽。现在我想获得所有插槽和每个插槽的持续时间。时间戳不是每隔一分钟或每分钟左右,两个条目之间的差异或多或少是随机的。

我考虑过子查询和分组,但我不知道如何解决这个问题,至少是否有可能。所以我的问题是:这是可能的:-)如果是的话,如何开始?我因为f-t改变问题而陷入困境......

1 个答案:

答案 0 :(得分:1)

如果你有一个现代版本的PG,你可以使用窗口函数做你想做的事情(在我的例子中,而不是时间戳,我有整数,但没关系): 我正在开发一个非窗口函数版本......

db=> select * from test1;
 time | status
------+--------
1 | f
2 | f
3 | f
4 | t
5 | f
6 | f
7 | f
8 | t
9 | f
10 | t

(8 rows)

以下是带窗口函数的查询:

 WITH a AS (
 SELECT time,rank() OVER (ORDER BY time) 
      FROM (
               SELECT status, time, lag(status,1)  OVER (ORDER BY time) AS ls
            FROM test1 
            ) AS x
             WHERE status AND NOT ls 
            -- select where the current status is true, the previous is false
       ),  -- a is now the endings of the slots
 b AS  (
     SELECT time, rank() OVER (ORDER BY time)
       FROM (
             SELECT  status, time, LAG(status,1)         
               OVER  (ORDER BY time)  AS ls
             FROM test1 
            ) AS x 
            WHERE (NOT status AND ls) OR (NOT status AND ls IS NULL) 
        )   -- b is now the beginning of the slots
    SELECT b.time as time1, a.time as time2 FROM a,b WHERE a.rank=b.rank;

  time1 | time2
------+------
1 |    4
5 |    8
9 |   10

以下是没有窗口函数的PG查询版本(实际上更短,但不太清晰)

  SELECT min(time) as time1, time2 FROM 
     (
         SELECT time, status,
          (
           SELECT time FROM test1 AS y
               WHERE y.time >= x.time
               ORDER BY (x.status = y.status)::int, y.time ASC LIMIT 1
          ) AS time2 
        FROM test1 AS x WHERE NOT status
     ) AS y GROUP BY y.time2 ORDER BY time2;
相关问题