How To check minimum Date in each observation and update flag dynamically

穿精又带淫゛_ 提交于 2020-01-02 10:26:53

问题


I have to check for minimum date each time and add 30 days to it and set the field accordingly.

For Example:

My Table:

ID    StartDate     EndDate
1     2017-01-01    2017-02-01
1     2017-01-09    2017-01-28
1     2017-04-01    2017-04-30
1     2017-04-05    2017-05-20
1     2017-04-20    2017-06-12
2     2017-06-02    2017-06-20
2     2017-06-14    2017-07-31
2     2017-06-14    2017-07-31
2     2017-06-19    2017-07-31
2     2017-06-19    2017-07-31

so, here min(startdate) is 2017-01-01. Now I add 30 days to it and my look up date is 2017-01-31. for any record which has start date less than this look up date I have to set flag_1.

My table will look like:

ID    StartDate     EndDate               flag
1     2017-01-01    2017-02-01            flag_1
1     2017-01-09    2017-01-28            flag_1
1     2017-04-01    2017-04-30            null
1     2017-04-05    2017-05-20            null
1     2017-04-20    2017-06-12            null
2     2017-06-02    2017-06-20            null
2     2017-06-14    2017-07-31            null
2     2017-06-14    2017-07-31            null
2     2017-06-19    2017-07-31            null
2     2017-06-19    2017-07-31            null

Now I have to look for next minimum startdate which is greater than previous look up date(2017-01-31).so my min start date would be 2017-04-01. Now I add 30 days to it and my new look up date is 2017-05-01. For all the records less than new look up start date 2017-05-01 and greater than previous look up date(2017-01-31) the flag will be flag_2 and this goes on for same ID till it reaches the last record for same ID.

My final table should look like:

ID    StartDate     EndDate               flag
1     2017-01-01    2017-02-01            flag_1
1     2017-01-09    2017-01-28            flag_1
1     2017-04-01    2017-04-30            flag_2
1     2017-04-05    2017-05-20            flag_2
1     2017-04-20    2017-06-12            flag_2
2     2017-06-02    2017-06-20            flag_1
2     2017-06-14    2017-07-31            flag_1
2     2017-06-14    2017-07-31            flag_1
2     2017-06-19    2017-07-31            flag_1
2     2017-06-19    2017-07-31            flag_1

i can get the first set of records by below code but unable to think of having this in a loop and having flag updated dynamically .

select  a.*,'flag_1' as flag from table  a
 join 
(select cast(min(startdate) as date) as minstartdate,cast(dateadd(day,30,min(startdate)) as date) as maxstartdate,ID from  table
group by ID) adate
on cast(adate.maxstartdate as date)> cast(a.startdate as date)
and adate.id=a.id
where a.id=1
order by startdate

Can anyone help me with this logic?


回答1:


Here is how I would approach it - there may be a recursive approach, but I don't use recursion unless it is absolutely necessary.

A couple of notes: I did the work in a temp table to make it easier to reset during development and testing, and I used an integer field for the flag to simplify the increment logic.

-- the setup
Create Table SO_Check_Min_Date
(
    ID Int
    , StartDate Date
    , EndDate Date
    , Flag Int
)

Insert Into dbo.SO_Check_Min_Date
(
    ID
    , StartDate
    , EndDate
)
Values
(1,     '2017-01-01',    '2017-02-01'),
(1,     '2017-01-09',    '2017-01-28'),
(1,     '2017-04-01',    '2017-04-30'),
(1,     '2017-04-05',    '2017-05-20'),
(1,     '2017-04-20',    '2017-06-12'),
(2,     '2017-06-02',    '2017-06-20'),
(2,     '2017-06-14',    '2017-07-31'),
(2,     '2017-06-14',    '2017-07-31'),
(2,     '2017-06-19',    '2017-07-31'),
(2,     '2017-06-19',    '2017-07-31')

-- the logic
Declare
@Flag As Int = 0
, @StartDate As Date
, @LookupDate As Date
, @ID As Int
, @PrevID As Int = 0;

Select
    *
Into
    #Temp_SO_Check
From SO_Check_Min_Date;

Select * From #Temp_SO_Check As tsc   -- to see that the flag field is blank

While Exists
(
    Select Top 1
                1
        From    #Temp_SO_Check
        Where   Flag Is Null
)
Begin
    Select Top 1
                @ID = ID
                , @StartDate = StartDate
        From    #Temp_SO_Check
        Where   Flag Is Null
        Order By
                ID
                , StartDate;

    If @PrevID <> @ID
        Begin
            Set @Flag = 1;
            Set @PrevID = @ID;
        End;
    Else
        Set @Flag = @Flag + 1;

    Set @LookupDate = DateAdd(Day, 30, @StartDate);

    Update
        #Temp_SO_Check
        Set
        Flag = @Flag
        Where
        ID = @ID
        And StartDate Between @StartDate
                    And     @LookupDate;
End;

Select * From #Temp_SO_Check As tsc      -- to see that it has been populated as desired



回答2:


Since this is the original question--I'm posting the answer here. I'd suggest ditching your loops all together. Here's a way with 2 CTE's and ZERO loops.

declare @table table (ID int, StartDate date, EndDate date)
Insert Into @table
(
    ID
    , StartDate
    , EndDate
)
Values
(1,     '2017-01-01',    '2017-02-01'),
(1,     '2017-01-09',    '2017-01-28'),
(1,     '2017-04-01',    '2017-04-30'),
(1,     '2017-04-05',    '2017-05-20'),
(1,     '2017-04-20',    '2017-06-12'),
(2,     '2017-06-02',    '2017-06-20'),
(2,     '2017-06-14',    '2017-07-31'),
(2,     '2017-06-14',    '2017-07-31'),
(2,     '2017-06-19',    '2017-07-31'),
(2,     '2017-06-19',    '2017-07-31')


;with cte as(
select
    t1.ID
    ,t1.StartDate
    ,t1.EndDate
    ,DT = (select min(StartDate) from @table t2  where t2.StartDate > DATEADD(day,30,t1.StartDate))
from
    @table t1),

cte2 as(
select
    ID
    ,StartDate
    ,EndDate
    ,dense_rank() over (order by isnull(DT,(select max(StartDate) from cte))) as Flag
from
    cte)

select 
    ID
    ,StartDate
    ,EndDate
    ,case when Flag % 2 = 0 then 2 else Flag % 2 end as Flag
from cte2


来源:https://stackoverflow.com/questions/45698391/how-to-check-minimum-date-in-each-observation-and-update-flag-dynamically

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!