我有一个包含日期列的表。
ID | Date
----|-----------
1 | 2000-01-01
2 | 2000-02-01
3 | 2000-02-01
4 | 2000-03-01
我需要一个为每行返回的选择,ID,日期和表格中所有日期的最小日期(大于当前日期)。
ID | Date | Next date
----+------------+------------
1 | 2000-01-01 | 2000-02-01
2 | 2000-02-01 | 2000-03-01
3 | 2000-02-01 | 2000-03-01
4 | 2000-03-01 | (NULL)
我的第一个方法是
SELECT id, date, LEAD (date, 1) OVER (ORDER BY date NULLS LAST) AS next_date
FROM t
但这只有在DATE列中的值是唯一的时才有效。
有什么想法吗?
答案 0 :(得分:6)
您可以使用windowing clause的分析函数。 lead()
不支持窗口子句,因此您需要使用类似min()
或first_value()
的句子:
FIRST_VALUE ("Date")
OVER (ORDER BY "Date" RANGE BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING)
默认的窗口子句为RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
,它会为您的所有行提供2000-01-01
的相同值,并且使用ROWS
窗口会遇到与您遇到的问题相同的问题{1}}重复日期(ID 2仍会获得lead()
;如果您使用2000-02-01
而不是2000-03-01
,则ID 4将获得ROWS BETWEEN CURRENT ROW...
而不是null。
使用此范围进行演示:
1 FOLLOWING
仅考虑日期值高于当前行的行。而这仍然只需要一次就能上台。
(我已将with t (ID, "Date") as (
select 1, date '2000-01-01' from dual
union all select 2, date '2000-02-01' from dual
union all select 3, date '2000-02-01' from dual
union all select 4, date '2000-03-01' from dual
)
select id, "Date", FIRST_VALUE ("Date") OVER (ORDER BY "Date"
RANGE BETWEEN 1 FOLLOWING AND UNBOUNDED FOLLOWING) AS next_date
FROM t;
ID Date NEXT_DATE
---------- ---------- ----------
1 2000-01-01 2000-02-01
2 2000-02-01 2000-03-01
3 2000-02-01 2000-03-01
4 2000-03-01
放在双引号中,因为"Date"
是一个保留字;从您的示例数据中,它看起来像一个带引号的标识符,但在查询中没有引用,所以它可能只是一个更明智的名字......)
答案 1 :(得分:5)
select * , (select min(t2.date) from table t2 where t2.date > t1.date)
from Table t1
上面的代码在sql server
中答案 2 :(得分:2)
回答我自己的问题。 ;-)(只是为那些在这篇文章中磕磕绊绊的人展示另一种选择)
另一种解决方案是使用子选择:
SELECT t.id,
t.date,
(SELECT MIN (t.date)
FROM t t2
WHERE t2.date > t.date)
AS next_date
FROM t;
答案 3 :(得分:1)
一种方法是创建一个包含不同日期及其直接前导值的CTE。然后,将此CTE加入日期的原始表格以获得最终结果。
WITH cte AS (
SELECT t.date,
LEAD(t.date, 1) OVER (ORDER BY t.date NULLS LAST) AS next_date
FROM (SELECT DISTINCT date FROM yourTable) t
)
SELECT
t1.ID,
t1.date,
t2.next_date
FROM yourTable t1
INNER JOIN cte t2
ON t1.date = t2.date
答案 4 :(得分:1)
这是另一种方法,没有“不同”:
select
ted.id,
ted.date_col,
(select
min(ted2.date_col)
from
test_date_v ted2
where
ted2.id != ted.id and
ted2.date_col > ted.date_col) next_date_col
from
test_date_v ted;