具有重复日期的领导 window 函数
Lead window function with duplicate dates
示例数据在这里:
http://rextester.com/VNGMF66717
我有以下数据:
ID Year Date
1111 2016 2016-02-28
1111 2016 2016-02-28
1111 2016 2016-03-31
1111 2016 2016-03-31
1111 2016 2016-03-31
1111 2016 2016-04-02
1111 2016 2016-05-31
1111 2016 2016-08-01
1111 2016 2016-12-11
1111 2017 2017-01-02
1111 2017 2017-01-02
1111 2017 2017-02-04
1111 2017 2017-02-04
1111 2017 2017-07-08
2222 2016 2016-02-11
2222 2016 2016-02-11
2222 2016 2016-03-28
2222 2016 2016-03-28
2222 2016 2016-03-28
2222 2016 2016-07-22
2222 2016 2016-12-31
2222 2017 2017-02-01
2222 2017 2017-02-14
我想直接在 SELECT 语句中使用引导 window 函数添加 NextDate 列(在每个 ID 和年份内重置), 而不是自我join 使用 RANK window 函数,就像我在提供的示例中所做的那样。
NextDate 列应该完全像这样
ID Year Date NextDate
1111 2016 2016-02-28 2016-03-31
1111 2016 2016-02-28 2016-03-31
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-04-02 2016-05-31
1111 2016 2016-05-31 2016-08-01
1111 2016 2016-08-01 2016-12-11
1111 2016 2016-12-11 NULL
1111 2017 2017-01-02 2017-02-04
1111 2017 2017-01-02 2017-02-04
1111 2017 2017-02-04 2017-07-08
1111 2017 2017-02-04 2017-07-08
1111 2017 2017-07-08 NULL
2222 2016 2016-02-11 2016-03-28
2222 2016 2016-02-11 2016-03-28
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-07-22 2016-12-31
2222 2016 2016-12-31 NULL
2222 2017 2017-02-01 2017-02-14
2222 2017 2017-02-14 NULL
有人知道如何正确执行此操作吗?
我认为您需要使用 outer apply
或子查询来执行此操作:
select cte.*, next_cte.date
from cte outer apply
(select top 1 cte2.*
from cte cte2
where cte2.id = cte.id and cte2.year = cte.year and
cte2.date > cte.date
order by cte2.date desc
) next_cte;
另一种方法是对不同的值执行 lead()
:
select cte.*, cte_next.next_date
from cte join
(select id, year, date,
lead(date) over (partition by id, year order by date) as next_date
from cte
group by id, year, date
) cte_next
ON cte.id = cte_next.id and cte.year = cte_next.year and cte.date = cte_next.date;
这可能不完全是您的意思,但是通过使用两个 window 函数和嵌套的 select : MAX(LEAD),您会得到想要的结果。
select
id, yr, dt
,MAX(nx_dt) OVER (PARTITION BY id, dt) nxt_dt
FROM
(
select
*
, LEAD(dt) OVER (PARTITION BY id, yr ORDER BY id, yr, dt) nx_dt
from
#testtable
) sub
/*
drop table #testtable
create table #testtable
(
id int, yr int, dt date
)
insert into #testtable
(
id, yr, dt
)
SELECT 1111,2016,'2016-02-28' union all
SELECT 1111,2016,'2016-02-28' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-04-02' union all
SELECT 1111,2016,'2016-05-31' union all
SELECT 1111,2016,'2016-08-01' union all
SELECT 1111,2016,'2016-12-11' union all
SELECT 1111,2017,'2017-01-02' union all
SELECT 1111,2017,'2017-01-02' union all
SELECT 1111,2017,'2017-02-04' union all
SELECT 1111,2017,'2017-02-04' union all
SELECT 1111,2017,'2017-07-08' union all
SELECT 2222,2016,'2016-02-11' union all
SELECT 2222,2016,'2016-02-11' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-07-22' union all
SELECT 2222,2016,'2016-12-31' union all
SELECT 2222,2017,'2017-02-01' union all
SELECT 2222,2017,'2017-02-14'
*/
另一种方法是使用相关 sub-query,如果 LEAD
returns 与 id 的当前日期相同,则获取一年中的下一个日期。
SELECT
[ID]
,[Year]
,[Date]
,CASE WHEN LEAD([Date]) OVER(PARTITION BY [ID],[Year] ORDER BY [Date]) = [Date]
THEN (SELECT MIN([Date]) FROM CTE WHERE [Date]>c.[Date] and [ID]=c.[ID] and [Year]=c.[Year])
ELSE LEAD([Date]) OVER(PARTITION BY [ID],[Year] ORDER BY [Date]) END AS [NextDate]
FROM CTE C
示例数据在这里:
http://rextester.com/VNGMF66717
我有以下数据:
ID Year Date
1111 2016 2016-02-28
1111 2016 2016-02-28
1111 2016 2016-03-31
1111 2016 2016-03-31
1111 2016 2016-03-31
1111 2016 2016-04-02
1111 2016 2016-05-31
1111 2016 2016-08-01
1111 2016 2016-12-11
1111 2017 2017-01-02
1111 2017 2017-01-02
1111 2017 2017-02-04
1111 2017 2017-02-04
1111 2017 2017-07-08
2222 2016 2016-02-11
2222 2016 2016-02-11
2222 2016 2016-03-28
2222 2016 2016-03-28
2222 2016 2016-03-28
2222 2016 2016-07-22
2222 2016 2016-12-31
2222 2017 2017-02-01
2222 2017 2017-02-14
我想直接在 SELECT 语句中使用引导 window 函数添加 NextDate 列(在每个 ID 和年份内重置), 而不是自我join 使用 RANK window 函数,就像我在提供的示例中所做的那样。
NextDate 列应该完全像这样
ID Year Date NextDate
1111 2016 2016-02-28 2016-03-31
1111 2016 2016-02-28 2016-03-31
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-03-31 2016-04-02
1111 2016 2016-04-02 2016-05-31
1111 2016 2016-05-31 2016-08-01
1111 2016 2016-08-01 2016-12-11
1111 2016 2016-12-11 NULL
1111 2017 2017-01-02 2017-02-04
1111 2017 2017-01-02 2017-02-04
1111 2017 2017-02-04 2017-07-08
1111 2017 2017-02-04 2017-07-08
1111 2017 2017-07-08 NULL
2222 2016 2016-02-11 2016-03-28
2222 2016 2016-02-11 2016-03-28
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-03-28 2016-07-22
2222 2016 2016-07-22 2016-12-31
2222 2016 2016-12-31 NULL
2222 2017 2017-02-01 2017-02-14
2222 2017 2017-02-14 NULL
有人知道如何正确执行此操作吗?
我认为您需要使用 outer apply
或子查询来执行此操作:
select cte.*, next_cte.date
from cte outer apply
(select top 1 cte2.*
from cte cte2
where cte2.id = cte.id and cte2.year = cte.year and
cte2.date > cte.date
order by cte2.date desc
) next_cte;
另一种方法是对不同的值执行 lead()
:
select cte.*, cte_next.next_date
from cte join
(select id, year, date,
lead(date) over (partition by id, year order by date) as next_date
from cte
group by id, year, date
) cte_next
ON cte.id = cte_next.id and cte.year = cte_next.year and cte.date = cte_next.date;
这可能不完全是您的意思,但是通过使用两个 window 函数和嵌套的 select : MAX(LEAD),您会得到想要的结果。
select
id, yr, dt
,MAX(nx_dt) OVER (PARTITION BY id, dt) nxt_dt
FROM
(
select
*
, LEAD(dt) OVER (PARTITION BY id, yr ORDER BY id, yr, dt) nx_dt
from
#testtable
) sub
/*
drop table #testtable
create table #testtable
(
id int, yr int, dt date
)
insert into #testtable
(
id, yr, dt
)
SELECT 1111,2016,'2016-02-28' union all
SELECT 1111,2016,'2016-02-28' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-03-31' union all
SELECT 1111,2016,'2016-04-02' union all
SELECT 1111,2016,'2016-05-31' union all
SELECT 1111,2016,'2016-08-01' union all
SELECT 1111,2016,'2016-12-11' union all
SELECT 1111,2017,'2017-01-02' union all
SELECT 1111,2017,'2017-01-02' union all
SELECT 1111,2017,'2017-02-04' union all
SELECT 1111,2017,'2017-02-04' union all
SELECT 1111,2017,'2017-07-08' union all
SELECT 2222,2016,'2016-02-11' union all
SELECT 2222,2016,'2016-02-11' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-03-28' union all
SELECT 2222,2016,'2016-07-22' union all
SELECT 2222,2016,'2016-12-31' union all
SELECT 2222,2017,'2017-02-01' union all
SELECT 2222,2017,'2017-02-14'
*/
另一种方法是使用相关 sub-query,如果 LEAD
returns 与 id 的当前日期相同,则获取一年中的下一个日期。
SELECT
[ID]
,[Year]
,[Date]
,CASE WHEN LEAD([Date]) OVER(PARTITION BY [ID],[Year] ORDER BY [Date]) = [Date]
THEN (SELECT MIN([Date]) FROM CTE WHERE [Date]>c.[Date] and [ID]=c.[ID] and [Year]=c.[Year])
ELSE LEAD([Date]) OVER(PARTITION BY [ID],[Year] ORDER BY [Date]) END AS [NextDate]
FROM CTE C