Sql Postgres 9.1-获取下一个值

Sql Postgres 9.1-获取下一个值,sql,postgresql,window-functions,Sql,Postgresql,Window Functions,我有一些数据(按“时间戳”排序),如下所示: Key | TimeStamp | Column3 | ColumnN --------------+-------------------------+-------------+-------------- 1 | 2012-01-01 08:00:23 | ... | ... 2 | 2012-01-0

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

      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   |     ...     |     ...
      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                  |     ...     |     ...
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
我需要为每条记录选择下一个(不仅仅是下一行)

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

      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   |     ...     |     ...
      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                  |     ...     |     ...
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
我一直在尝试使用一个窗口函数来实现这一点,但我没有得到这个结果。有什么想法吗?

您可以通过如下方式选择“下一步”值:

      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   |     ...     |     ...
      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                  |     ...     |     ...
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函数。

这应该比相关子查询快得多:

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

  • 使用获得CTE中没有差距的排名
  • 然后,
    LEFT JOIN
    通过偏移量
    1
    将结果与自身的
    DISTINCT
    版本进行连接,以获得“下一个”时间戳(并且仅一个)
  • 或者,对于
    y
    ,您可以使用
    groupby 1,2
    而不是
    DISTINCT
    。我希望这里的
    DISTINCT
    速度更快,因为排序顺序与窗口函数的
    orderby
    一致。但是请检查
    解释分析
    并亲自查看

即使比dense\u rank更冷,您也可以使用窗口功能:

SELECT Key, ts, lead(ts) OVER(ORDER BY ts ASC)
FROM tbl;
不知羞耻地从欧文的回答中盗取了链接


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

“我一直在尝试使用”-您应该向我们展示这些尝试。这也是我提出的解决方案之一,但(正如您指出的)它太慢了。您建议在函数中加入什么使其运行快速?此表有数亿条记录。@Losshorse只需编写一个函数,通过一个简单的光标从表中按时间顺序选择*(从旧到新)。对于游标
中的每一行,返回NEXT
之前存储在变量中的整行+
end\u时间戳。