SQL Server Find record which are greater or equal to 30 days from previous record

wecizke3  于 2023-04-19  发布在  其他
关注(0)|答案(2)|浏览(88)

I know we can use lag function to get the records who are greater than 30 days of the previous record.

I have a requirement attached in a image as shown in image

1st row is the start and I use that date to compare with the successive record, as soon as I find a record which is >=30 days, I need to take the date of that record and start comparing with successive records until I find a new record >= 30 days.

At the end after doing this I need records who are 30 days apart or null (first record)

Any way in SQL we can achieve this?

I tried using the lag function but that will compare with the previous record only , this will result in records which are >= 30days from the first record getting eliminated.

declare @Payment table 
(
    PersonId int
    , fromdate date
    , todate date
)
insert @Payment 
(PersonId, fromdate , todate )
values (1, '07/05/2014' , '07/06/2014' )
,(1, '07/15/2014' , '07/16/2014' )
,(1, '09/23/2014' , '09/24/2014')
,(1, '10/15/2014' , '10/16/2014')
,(1, '10/30/2014' , '10/31/2014')
,(2,  '07/20/2014' ,  '07/25/2014')
,(2, '08/20/2014' , '08/21/2014')
,(2, '09/21/2014' , '09/22/2014')

select * from @Payment

;with cte as
(select PersonId , fromdate , todate
       ,datediff(d
                ,  lag(todate) over (partition by PersonId order by fromdate)
                , fromdate)DaysSinceLastindex
 from @Payment )
select  PersonId , fromdate , todate , DaysSinceLastindex
from cte
where DaysSinceLastindex >= 30 or DaysSinceLastindex is null

Expected output is shown the image attached enter image description here

afdcj2ne

afdcj2ne1#

As I understand your question, we need a recursive query here:

with 
    data as (
        select p.*, row_number() over(partition by personid order by fromdate) rn
        from @payment p
    ),
    rcte as (
        select d.*, todate as refdate from data d where rn = 1
        union all
        select d.*, 
            case when datediff(d, r.refdate, d.fromdate) < 30 then r.refdate else d.todate end
        from rcte r
        inner join data d on d.personid = r.personid and d.rn = r.rn + 1
    )
select * from rcte where refdate = todate order by personid, fromdate

The first CTE enumerates the payments of each person. Then, the recursive query starts from the first payments, and processes rows in order, while keeping track of the "reference" start date and changing it when its gap with the current record exceeds 30 days. The last step is to just filter on the "first" record per group.

PersonIdfromdatetodaternrefdate
12014-07-052014-07-0612014-07-06
12014-09-232014-09-2432014-09-24
12014-10-302014-10-3152014-10-31
22014-07-202014-07-2512014-07-25
22014-09-212014-09-2232014-09-22

fiddle

If a person may have more than 100 payments, then you need option (maxrecursion 0) at the end of your query.

n1bvdmb6

n1bvdmb62#

with cte as (
  select PersonId , fromdate , todate,
       lag(todate) over (partition by PersonId order by fromdate) as lag_todate
 from Payment 
),
cte2 as (
  select  *,
        datediff(d, lag_todate, fromdate ) DaysSinceLastindex,
        MIN(case when datediff(d, lag_todate, fromdate) >=30 then todate end) 
                     over (partition by PersonId order by fromdate) as new_fromdate
  from cte
),
cte3 as (
  select *, case when new_fromdate is null
               then datediff(d, lag_todate, fromdate )
               else datediff(d, new_fromdate, fromdate ) end as datediff
  from cte2
)
select PersonId, fromdate, todate, lag_todate, DaysSinceLastindex, 
  case when GREATEST(DaysSinceLastindex, datediff) >=30 OR lag_todate is null then 'YES' end as EXPECTED
from cte3
order by PersonId, fromdate

First cte to get previous todate.

cte2 to get DaysSinceLastindex and the new fromdate to compare with if it is >=30 days.

cte3 to get datediff between current date and the starting date or the with new record if exist

Result :

PersonId    fromdate    todate      lag_todate  DaysSinceLastindex  EXPECTED
1           2014-07-05  2014-07-06  null        null                YES
1           2014-07-15  2014-07-16  2014-07-06  9                   
1           2014-09-23  2014-09-24  2014-07-16  69                  YES
1           2014-10-15  2014-10-16  2014-09-24  21                  
1           2014-10-30  2014-10-31  2014-10-16  14                  YES
2           2014-07-20  2014-07-25  null        null                YES
2           2014-08-20  2014-08-21  2014-07-25  26                  
2           2014-09-21  2014-09-22  2014-08-21  31                  YES

Demo here

相关问题