Sql Code help pulling date range before an status

  • Hi All,

    Hello,

    I have an issue in finding out the date range and id previous to an event. here I want to pull id and dates(start and end dates) before a status urgent is high. for example id 111 urgent date range is '2017-01-04 00:00:00.000' and 2017-03-07 00:00:00.000' , now I need to check if the previous status is high and if it high I need to pull id and date ranges of high . i.e; here '2016-10-31 00:00:00.000' and '2017-01-03 00:00:00.000' . Similar way for id 222 date range for urgent is 2017-01-04 00:00:00.000 and '2017-03-07 00:00:00.000' and prior status is medium i.e; not high I not need to return this id and dates. so my requirement is I need to check for current status is intensive and if very previous status is high I need to pull data or else empty. here I will only get 111 details. let me know if it is not clear.

    Thanks in advance. below is the sample data.

    declare @stats table

    (id int,

    status varchar(10),

    startdate datetime,

    enddate datetime


    )

    insert

    into @stats values (111,'medium','2014-06-01 00:00:00.000','2015-05-13 00:00:00.000')

    insert into @stats values (111,'high','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000')

    insert into @stats values (111,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000')

    insert into @stats values (222,'high','2015-08-13 00:00:00.000','2015-05-13 00:00:00.000')

    insert into @stats values (222,'medium','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000')

    Insert into @stats values (222,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000')


    Select * From @stats

  • There are a couple of things that aren't clear:

    1.) Are time spans ever overlapping?
    2.) Are you seeking only data where an ID has an "urgent" status?
    3.) Does any ID value have more than one "urgent" status?

    It would be very helpful for you to specify the exact output you would expect given your sample data.

    Steve (aka sgmunson) 🙂 🙂 🙂
    Rent Servers for Income (picks and shovels strategy)

  • Just in case you want what I think you want:
    CREATE TABLE #stats (
        id int,
        [status] varchar(10),
        startdate datetime,
        enddate datetime
    );
    INSERT INTO #stats
        VALUES    (111,'medium','2014-06-01 00:00:00.000','2015-05-13 00:00:00.000'),
                (111,'high','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000'),
                (111,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000'),
                (222,'high','2015-08-13 00:00:00.000','2015-05-13 00:00:00.000'),
                (222,'medium','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000'),
                (222,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000');

    WITH LEAD_VALUES AS (

        SELECT id, [status], startdate, enddate,
            CASE [status] WHEN 'high' THEN LEAD([status], 1, NULL) OVER(PARTITION BY id ORDER BY startdate, enddate) ELSE NULL END AS LEAD_STATUS
        FROM #stats
    )
    SELECT L.id
        , L.[status]
        , L.startdate
        , L.enddate
    FROM LEAD_VALUES AS L
    WHERE L.[status] = 'urgent'
        OR
            (
            L.[status] = 'high'
            AND
            L.LEAD_STATUS = 'urgent'
            )
    ORDER BY L.id, L.startdate, L.enddate;

    DROP TABLE #stats;

    Steve (aka sgmunson) 🙂 🙂 🙂
    Rent Servers for Income (picks and shovels strategy)

  • Thank you so much for your reply,

    I only need high id's and dates if there anything available previous to urgent. in this case I need only 111, high and dates. Thank you !

  • dhanekulakalyan - Wednesday, October 11, 2017 7:36 AM

    Thank you so much for your reply,

    I only need high id's and dates if there anything available previous to urgent. in this case I need only 111, high and dates. Thank you !

    Replacing your
    Select * From @stats

    with something like 
    select id, previousstatus as status, previousstartdate as startdate, previousenddate as enddate
    from
        (select
            id,
            status,
            lag(status,1,'na') over (partition by id order by startdate) as previousstatus,
            lag(startdate,1) over (partition by id order by startdate) as previousstartdate,
            lag(enddate,1) over (partition by id order by enddate) as previousenddate
        from @stats
        ) a
    where status = 'urgent' and previousstatus = 'high'

    should get you

    id    status    startdate    enddate
    111    high    2016-10-31 00:00:00.000    2017-01-03 00:00:00.000

  • sgmunson - Wednesday, October 11, 2017 6:38 AM

    Just in case you want what I think you want:
    CREATE TABLE #stats (
        id int,
        [status] varchar(10),
        startdate datetime,
        enddate datetime
    );
    INSERT INTO #stats
        VALUES    (111,'medium','2014-06-01 00:00:00.000','2015-05-13 00:00:00.000'),
                (111,'high','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000'),
                (111,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000'),
                (222,'high','2015-08-13 00:00:00.000','2015-05-13 00:00:00.000'),
                (222,'medium','2016-10-31 00:00:00.000','2017-01-03 00:00:00.000'),
                (222,'urgent','2017-01-04 00:00:00.000','2017-03-07 00:00:00.000');

    WITH LEAD_VALUES AS (

        SELECT id, [status], startdate, enddate,
            CASE [status] WHEN 'high' THEN LEAD([status], 1, NULL) OVER(PARTITION BY id ORDER BY startdate, enddate) ELSE NULL END AS LEAD_STATUS
        FROM #stats
    )
    SELECT L.id
        , L.[status]
        , L.startdate
        , L.enddate
    FROM LEAD_VALUES AS L
    WHERE L.[status] = 'urgent'
        OR
            (
            L.[status] = 'high'
            AND
            L.LEAD_STATUS = 'urgent'
            )
    ORDER BY L.id, L.startdate, L.enddate;

    DROP TABLE #stats;

    Thank you and this works for me, I changed LEAD to LAG because I need previous status. Thanks again for help

  • SQLPirate - Wednesday, October 11, 2017 8:08 AM

    dhanekulakalyan - Wednesday, October 11, 2017 7:36 AM

    Thank you so much for your reply,

    I only need high id's and dates if there anything available previous to urgent. in this case I need only 111, high and dates. Thank you !

    Replacing your
    Select * From @stats

    with something like 
    select id, previousstatus as status, previousstartdate as startdate, previousenddate as enddate
    from
        (select
            id,
            status,
            lag(status,1,'na') over (partition by id order by startdate) as previousstatus,
            lag(startdate,1) over (partition by id order by startdate) as previousstartdate,
            lag(enddate,1) over (partition by id order by enddate) as previousenddate
        from @stats
        ) a
    where status = 'urgent' and previousstatus = 'high'

    should get you

    id    status    startdate    enddate
    111    high    2016-10-31 00:00:00.000    2017-01-03 00:00:00.000

    Thank you for your help ,will use lag for this scenario. Thanks again

  • dhanekulakalyan - Wednesday, October 11, 2017 5:28 PM

    SQLPirate - Wednesday, October 11, 2017 8:08 AM

    dhanekulakalyan - Wednesday, October 11, 2017 7:36 AM

    Thank you so much for your reply,

    I only need high id's and dates if there anything available previous to urgent. in this case I need only 111, high and dates. Thank you !

    Replacing your
    Select * From @stats

    with something like 
    select id, previousstatus as status, previousstartdate as startdate, previousenddate as enddate
    from
        (select
            id,
            status,
            lag(status,1,'na') over (partition by id order by startdate) as previousstatus,
            lag(startdate,1) over (partition by id order by startdate) as previousstartdate,
            lag(enddate,1) over (partition by id order by enddate) as previousenddate
        from @stats
        ) a
    where status = 'urgent' and previousstatus = 'high'

    should get you

    id    status    startdate    enddate
    111    high    2016-10-31 00:00:00.000    2017-01-03 00:00:00.000

    Thank you for your help ,will use lag for this scenario. Thanks again

    Try changing your perspective.  You need three fields from one record ('high') and only one field from the other record ('urgent') and one field can come from either record (id), so why are you using the 'urgent' record as your reference instead of using the 'high' record?


    select id, status, startdate, enddate
    from
      (select 
       id, 
       status, 
       lead(status,1,'na') over (partition by id order by startdate) as nextstatus,
       startdate,
       enddate
      from @stats 
      ) a
    where status = 'high' and nextstatus = 'urgent'

    By changing the reference to the record with the most fields we want, we now only need to do one lookup on another record instead of three.

    Drew

    J. Drew Allen
    Business Intelligence Analyst
    Philadelphia, PA

  • drew.allen - Thursday, October 12, 2017 8:07 AM

    Try changing your perspective.  You need three fields from one record ('high') and only one field from the other record ('urgent') and one field can come from either record (id), so why are you using the 'urgent' record as your reference instead of using the 'high' record?


    select id, status, startdate, enddate
    from
      (select 
       id, 
       status, 
       lead(status,1,'na') over (partition by id order by startdate) as nextstatus,
       startdate,
       enddate
      from @stats 
      ) a
    where status = 'high' and nextstatus = 'urgent'

    By changing the reference to the record with the most fields we want, we now only need to do one lookup on another record instead of three.

    Drew

    That's a very good point and a much better solution.

Viewing 9 posts - 1 through 8 (of 8 total)

You must be logged in to reply to this topic. Login to reply