2017-09-26 1 views
1

J'ai quelques enregistrements ci-dessous. Pour chaque client, un seul enregistrement peut avoir END_DATE=12/31/9998.SQL Server 2008: Comment mettre à jour la colonne de date de fin pour l'enregistrement précédent

J'ai donc besoin de mettre à jour l'enregistrement précédent en fonction de la colonne EFFECT_DATE.

Par exemple, je dois mettre à jour le END_DATE de ID=2 de 12/31/9998 à 7/17/2017 pour CLT_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

Pourquoi ne pas laisser tomber la colonne de END_DATE et de calculer à l'aide d'une cte récursive lorsque vous interrogez les données? –

+0

vous devriez voir ma réponse pour sql 2008 conforme version – DhruvJoshi

+0

@SeanLange - autant que je voudrais recommander cela aussi (ou quelque chose avec 'LEAD()'), ces requêtes peuvent consommer beaucoup de ressources. Comme ces données sont souvent assez statiques, il est généralement préférable de mettre en cache la date de fin, bien qu'il soit possible d'en faire une colonne calculée. Cela dit, je recommande absolument d'en faire une borne supérieure ** ** ("<"), de sorte que l'interroger ne se heurte pas à des situations amusantes avec des conversions de type (c.-à-d. comme date d'entrée en vigueur de la ligne suivante). –

Répondre

1

Vous pouvez utiliser lead pour obtenir la prochaine date d'effet et soustraire un jour à mettre à jour la date de fin de la ligne en cours .

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 

Pour SQL Server 2008, utilisez

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

J'utilise SQL Server 2008 – Ice

1

Une solution basée sur l'assemblage et le regroupement des données connexes. Ces jours-ci, j'utilise souvent des CTE, mais avant qu'ils ne soient populaires, il aurait fallu envisager d'utiliser quelque chose comme ça.

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

vous pouvez utiliser la requête comme ci-dessous pour une SQL 2008 réponse conforme

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