2017-09-26 53 views
1

我在下面有一些記錄。對於每個客戶,只有一條記錄可以有END_DATE=12/31/9998SQL Server 2008:如何更新以前記錄的結束日期列

所以我需要結束日期基於EFFECT_DATE列以前的記錄。

例如,我需要從 12/31/9998更新ID=2END_DATE7/17/2017CLT_NBR=12375

ID CLT_NBR IS_PRIMARY EFFECT_DATE END_DATE 
----------------------------------------------- 
1 12375  1   8/13/2015 9/30/2015 
2 12375  1   10/1/2015 12/31/9998 
3 12375  1   7/18/2017 12/31/9998 
4 12331  1   2/3/2016 7/8/2016 
5 12331  1   7/9/2016 12/31/9998 
+1

爲什麼不降END_DATE列和使用遞歸CTE在查詢計算它數據? –

+0

你應該看到我的答案爲sql 2008兼容版本 – DhruvJoshi

+0

@SeanLange - 儘可能多地我也推薦這個(或者用'LEAD()')的東西,那些查詢會消耗大量資源。由於這些數據通常相當靜態,所以緩存結束日期通常會更好,儘管可以將其計算爲列。也就是說,我絕對建議將它作爲**獨佔**('<')上限,以便查詢它不會遇到類型轉換的有趣情況(即非最大值結束日期應該相同作爲下一行的生效日期)。 –

回答

1

您可以使用lead獲得下一個生效日期和減去一天來更新當前行的結束日期。

with cte as (select t.*,coalesce(dateadd(day,-1,lead(effect_date) over(partition by clt_nbr order by id),'9998-12-31') as new_end_date 
      from tbl t) 
update cte 
set end_date=new_end_date 

對於SQL Server 2008,使用

with rownums as (select t.*,row_number() over(partition by clt_nbr order by id) as rnum from tbl t) 
,cte as (select r1.*,dateadd(day,-1,coalesce(r2.effect_date,'9999-01-01')) as new_end_date 
     from rownums r1 
     left join rownums r2 on r1.clt_nbr=r2.clt_nbr and r1.rnum=r2.rnum-1 
     ) 
update cte 
set end_date=new_end_date 
+0

我正在使用sql server 2008 – Ice

1

基礎上加入和將相關數據的解決方案。現在我經常使用CTE,但在它們很受歡迎之前,我們不得不考慮使用這樣的東西。

select * 
into ##test1 
from 
(
select ID = 1, CLT_NBR = 12375, IS_PRIMARY = 1, EFFECT_DATE = cast('8/13/2015' as date), END_DATE = cast('9/30/2015' as date) 
union all select ID = 2, CLT_NBR = 12375, IS_PRIMARY = 1, EFFECT_DATE = cast('10/1/2015' as date), END_DATE = cast('12/31/9998' as date) 
union all select ID = 3, CLT_NBR = 12375, IS_PRIMARY = 1, EFFECT_DATE = cast('7/18/2017' as date), END_DATE = cast('12/31/9998' as date) 
union all select ID = 4, CLT_NBR = 12331, IS_PRIMARY = 1, EFFECT_DATE = cast('2/3/2016' as date), END_DATE = cast('7/8/2016' as date) 
union all select ID = 5, CLT_NBR = 12331, IS_PRIMARY = 1, EFFECT_DATE = cast('7/9/2016' as date), END_DATE = cast('12/31/9998' as date) 
) x 

select * from ##test1 

select t.ID, t.CLT_NBR, t.IS_PRIMARY, t.EFFECT_DATE, END_DATE = isnull(dateadd(day,-1,min(t_next.EFFECT_DATE)),'9998-12-31') 
from ##test1 t 
left join ##test1 t_next on t_next.CLT_NBR = t.CLT_NBR and t_next.effect_date > t.effect_date 
group by t.ID, t.CLT_NBR, t.IS_PRIMARY, t.EFFECT_DATE 

update t 
set END_DATE = helper.END_DATE 
from ##test1 t 
left join 
(
    select t.ID, t.CLT_NBR, t.IS_PRIMARY, t.EFFECT_DATE, END_DATE = isnull(dateadd(day,-1,min(t_next.EFFECT_DATE)),'9998-12-31') 
    from ##test1 t 
    left join ##test1 t_next on t_next.CLT_NBR = t.CLT_NBR and t_next.effect_date > t.effect_date 
    group by t.ID, t.CLT_NBR, t.IS_PRIMARY, t.EFFECT_DATE 
) helper on helper.id = t.id 

select * from ##test1 

drop table ##test1 
0

您可以使用查詢類似下面的SQL 2008兼容的答案

CREATE TABLE yourTbl (ID int,CLT_NBR int,IS_PRIMARY int,EFFECT_DATE date, END_DATE date) 
INSERT INTO yourTbl VALUES 
(1 ,12375,1,'8/13/2015','9/30/2015') 
,(2 ,12375,1,'10/1/2015','12/31/9998') 
,(3 ,12375,1,'7/18/2017','12/31/9998') 
,(4 ,12331,1, '2/3/2016','7/8/2016') 
,(5 ,12331,1, '7/9/2016','12/31/9998') 




;with y as 
(
SELECT 
    *, 
    ROW_NUMBER() OVER(PARTITION BY CLT_NBR ORDER BY EFFECT_DATE DESC) R 
FROM yourTbl WHERE END_DATE ='12/31/9998' 
) 


UPDATE y1 
SET y1.END_DATE= y2.EFFECT_DATE 
FROM 
y y1 JOIN y y2 
ON y1.R=y2.R+1 and y1.CLT_NBR=y2.CLT_NBR 


select * from yourTbl 

See working demo

相關問題