2017-02-14 51 views
4

的樣本數據在這裏:
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 

我想添加一個NextDate列(每個ID和一年內重置)使用RANK窗口函數直接在SELECT語句中使用引導窗口函數而不是自加入,正如我在提供的示例中所做的那樣。

的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 

任何人都知道如何正確地做到這一點?

+0

你試過了嗎? – Lali

+0

請將您的rextester代碼添加到帖子以避免依賴鏈接。 – Tanner

+2

@Lali:在鏈接中,用戶提供的示例數據以及他嘗試的 – TheGameiswar

回答

3

這可能不是你的意思到底是什麼,但通過使用兩個窗口函數和一個嵌套的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' 
*/ 
+0

喜歡它...... –

3

我這一點,你需要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; 
+0

避免使子查詢/外部應用獲得所需結果是不可能的(或者甚至不可行)? –

+0

@EmilVissing。 。 。我不這麼認爲,但也許別人會提出一個解決方案。 –

+1

加入...上... –

0

另一種方法是使用相關子查詢,它獲取下一個日期在一年內如果LEAD返回相同的日期作爲當前日期的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