Reputation: 1570
I have some data (sorted by "TimeStamp") that looks like this:
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 | ... | ...
I need to select the next value (not merely the next row) of "TimeStamp" for each record.
For example, the above data would look like this:
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 | ... | ...
I have been trying to use a window function for this, but I have not been able to get this result. Any thoughts?
Upvotes: 2
Views: 1895
Reputation: 35927
Even cooler than dense_rank, you can use the lead
window function :
SELECT Key, ts, lead(ts) OVER(ORDER BY ts ASC)
FROM tbl;
Shamelessly stolen sqlfiddle link from Erwin's answer.
Edit: Hmm, actually it doesn't work exactly like you described, since it won't select the next higher value when two values are equal. I won't delete the answer because I think it can be useful in this context, but I'll mark it as community wiki.
Upvotes: 5
Reputation: 656714
This should be much faster than correlated subqueries:
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
dense_rank()
to get a ranking without gaps in a CTE.LEFT JOIN
the result to a DISTINCT
version of itself by an offset of 1
to get the "next" timestamp (and only a single one).GROUP BY 1,2
instead of DISTINCT
for y
. I'd expect DISTINCT
to be faster here, because the sort order agrees with the ORDER BY
of the window function. But check with EXPLAIN ANALYZE
and see for yourself.Upvotes: 4
Reputation: 28541
You can get the "next" value with subselect like this:
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
But this query can be slow. If you need it to be fast - just write a simple PL/SQL function.
Upvotes: 1