Postgres 9.1 - 获得下一个价值

时间:2013-02-12 22:34:36

标签: sql postgresql window-functions

我有一些数据(按“TimeStamp”排序),如下所示:

      Key     |        TimeStamp        |   Column3   |   ColumnN
--------------+-------------------------+-------------+--------------
       1      |   2012-01-01 08:00:23   |     ...     |     ...
       2      |   2012-01-01 08:01:07   |     ...     |     ...
       3      |   2012-01-01 08:02:56   |     ...     |     ...
       6      |   2012-01-01 08:02:56   |     ...     |     ...
       4      |   2012-01-01 08:03:39   |     ...     |     ...
       5      |   2012-01-01 08:04:32   |     ...     |     ...

我需要为每条记录选择“TimeStamp”的下一个不仅仅是下一行)。

例如,上述数据如下所示:

      Key     |          Begin          |           End           |   Column3   |   ColumnN
--------------+-------------------------+-------------------------+-------------+--------------
       1      |   2012-01-01 08:00:23   |   2012-01-01 08:01:07   |     ...     |     ...
       2      |   2012-01-01 08:01:07   |   2012-01-01 08:02:56   |     ...     |     ...
       3      |   2012-01-01 08:02:56   |   2012-01-01 08:03:39   |     ...     |     ...
       6      |   2012-01-01 08:02:56   |   2012-01-01 08:03:39   |     ...     |     ...
       4      |   2012-01-01 08:03:39   |   2012-01-01 08:04:32   |     ...     |     ...
       5      |   2012-01-01 08:04:32   |   NULL                  |     ...     |     ...

我一直在尝试使用窗口函数,但是我无法得到这个结果。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

甚至比dense_rank更酷,你可以使用lead窗口函数:

SELECT Key, ts, lead(ts) OVER(ORDER BY ts ASC)
FROM tbl;

从欧文的回答中无耻地偷走sqlfiddle链接。

编辑:嗯,实际上它并不像你描述的那样完全,因为当两个值相等时它不会选择下一个更高的值。我不会删除答案,因为我认为它在这种情况下很有用,但我会将其标记为社区维基。

答案 1 :(得分:4)

这应该比相关子查询 更快

WITH x AS (
   SELECT *, dense_rank() OVER (ORDER BY ts) AS rnk
   FROM   tbl
   )
SELECT x.key, x.ts AS ts_begin, y.ts As ts_end
FROM   x
LEFT   JOIN (SELECT DISTINCT ts, rnk FROM x) y ON y.rnk = (x.rnk + 1)
ORDER  BY x.ts

->sqlfiddle

  • 使用window function dense_rank()在CTE中获得无差距的排名
  • 然后LEFT JOIN将结果发送到DISTINCT版本的偏移量为1以获取“下一个”时间戳(并且只有一个)。
  • 或者,您可以使用GROUP BY 1,2代替DISTINCT y。我希望DISTINCT在这里更快,因为排序顺序与窗口函数的ORDER BY一致。但请查看EXPLAIN ANALYZE并自行查看。

答案 2 :(得分:1)

您可以使用以下子选项获取“下一个”值:

SELECT "Key", 
       t1.Timestamp as "Begin", 
       (SELECT min(t2."TimeStamp") 
        FROM the_table t2
        WHERE t2."TimeStamp" > t1."TimeStamp") as "End",
       column3, ...
FROM the_table t1

但是这个查询可能很慢。如果你需要快速 - 只需编写一个简单的PL / SQL函数。