question

itzpriya21 avatar image
itzpriya21 asked

Split the Overlap date range

I am new to SQL Server. I have a situation to split the overlap date range. I searched this FAQ and got a pretty much close solution. Here it goes that one.
 
==============

    declare @tbl table
    (
        category    int,
        startdate   datetime,
        enddate     datetime
    )
    insert into @tbl
    select  10, '1/1/2010 17:49:59', '10/30/2010 17:49:49' union all
    select  10, '5/3/2010 17:49:59', '10/30/2010 17:49:59' union all
    select  11, '1/1/2010 17:49:59', '10/30/2011 17:49:59' union all
    select  11, '5/3/2010 17:49:59', '10/30/2010 17:49:59'
    
    ; with cte as
    (
        select  category, dte = startdate, f = 'S'
        from    @tbl
        union
        select  category, dte = enddate, f = 'E'
        from    @tbl
    ),
    cte2 as
    (
        select  *, row_no = row_number() over (partition by category order by dte)
        from    cte
    )
    select  category    = c1.category, 
    startdate   = case  when c1.f = 'E'
                then dateadd(S, 1, c1.dte)
                else c1.dte
                end,
    enddate     = case  when c2.f = 'S' 
                then dateadd(s, -1, c2.dte) 
                else c2.dte 
                end
from    cte2 c1
    inner join cte2 c2  on  c1.category = c2.category
                and c1.row_no   = c2.row_no - 1


category startdate enddate ----------- ----------------------- ----------------------- 10 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 10 2010-05-03 17:49:59.000 2010-10-30 17:49:49.000 10 2010-10-30 17:49:50.000 2010-10-30 17:49:59.000 11 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 11 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-10-30 17:50:00.000 2011-10-30 17:49:59.000 (6 row(s) affected) But my results should show like the following. category startdate enddate - - - 10 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 10 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 11 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-10-30 17:50:00.000 2011-10-30 17:49:59.000 (5 row(s) affected) Because for the 10 seconds, no need to get the new one. I should be combined with the previous one. The date range actually ends at 17:49:59 only. Any suggestion on this?... Your help is greatly appreciated. --- [Edit] Thanks Squirrel for your help. I am giving some more cases here. For this case select 10, '1/1/2010 17:49:59', '10/30/2010 17:49:59' union all select 10, '5/3/2010 17:49:59', '10/30/2010 17:49:29' union all select 11, '1/1/2010 17:49:59', '10/30/2011 17:49:59' union all select 11, '5/3/2010 17:49:59', '10/30/2010 17:49:59' The results should be like the following and it works fine. category startdate enddate 10 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 10 2010-05-03 17:49:59.000 2010-10-30 17:49:29.000 10 2010-10-30 17:49:30.000 2010-10-30 17:49:59.000 11 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 11 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-10-30 17:50:00.000 2011-10-30 17:49:59.000 (6 row(s) affected) But for this case select 10, '1/1/2010 17:49:59', '10/30/2010 17:49:29' union all select 10, '5/3/2010 17:49:59', '10/30/2010 17:49:59' union all select 11, '1/1/2010 17:49:59', '10/30/2011 17:49:59' union all select 11, '5/3/2010 17:49:59', '10/30/2010 17:49:59' union all select 12, '1/1/2010 17:49:59', '10/30/2010 17:49:09' union all select 12, '5/3/2010 17:49:59', '10/30/2010 17:49:59' I should get the results like the following. I am not getting this with the SQL which I have. category startdate enddate 10 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 10 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 11 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-10-30 17:50:00.000 2011-10-30 17:49:59.000 12 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 12 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 (7 row(s) affected)
t-sqldate-range
11 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Oleg avatar image Oleg commented ·
@itzpriya21 Can you elaborate a bit on the requirement? Do you have a certain criteria for a decision of whether to include or discard the rows which you consider as too small in time difference? So far it appears that Squirrel's solution works and you can modify it to toggle the 10 seconds to some other value if you need to.
1 Like 1 ·
Oleg avatar image Oleg commented ·
@itzpriya21 Thank you, I think that I get it now. You don't need any records in your results which are caused by the records generated from 2 end dates right? It does not matter 10 seconds or more or less. How many original records per category do you have? Is it always 2 or there could be more?
1 Like 1 ·
itzpriya21 avatar image itzpriya21 commented ·
The criteria is split. **For example:** select 10, '1/1/2010 17:49:59', '10/30/2010 **17:49:59**' union all select 10, '5/3/2010 17:49:59', '10/30/2010 **17:49:49**' union all in this case, it should create a new row with 10 seconds and it does. But in the current case, it should not create a new row for 10 seconds because the second row which ends 10 seconds longer is the latest one. The difference is here 10 seconds. There is a posibility that it can be more. Hope this helps.
0 Likes 0 ·
itzpriya21 avatar image itzpriya21 commented ·
Guys any update?
0 Likes 0 ·
itzpriya21 avatar image itzpriya21 commented ·
Ok... I am sorry for not giving full details. For category 10, when I run a query based on time frame, it should return one row only. But from 5/3/2010 to 10/30/2010 it returns 2 records. So, the overlapped one got removed and created a new row. It works fine. Because the second row in category 10 ends 10 seconds higher than the first one and the second one is the latest, it should not create a new group for 10 seconds. For this case I can use Squirrel's solution. But in some situations, it may be more than 10 seconds. In that case, I have to modify the 10 seconds to someting else. Is there any way it works even if the difference is other than 10 seconds? Hope this helps.
0 Likes 0 ·
Show more comments
Squirrel avatar image
Squirrel answered
i added another cte to perform the logic to remove rows with datetime falls into the 10 secs criteria declare @tbl table ( category int, startdate datetime, enddate datetime ) insert into @tbl select 10, '1/1/2010 17:49:59', '10/30/2010 17:49:49' union all select 10, '5/3/2010 17:49:59', '10/30/2010 17:49:59' union all select 11, '1/1/2010 17:49:59', '10/30/2011 17:49:59' union all select 11, '5/3/2010 17:49:59', '10/30/2010 17:49:59' ; with cte as ( select category, dte = startdate, f = 'S' from @tbl union select category, dte = enddate, f = 'E' from @tbl ), cte2 as ( select *, row_no = row_number() over (partition by category order by dte) from cte ), cte3 as -- logic to remove dates that is within 10 secs ( select c1.category, c1.dte, c1.f, row_no = row_number() over (partition by c1.category order by c1.dte) from cte2 c1 left join cte2 c2 on c1.category = c2.category and c1.row_no = c2.row_no - 1 where c2.row_no is null or c1.dte < dateadd(second, -10, c2.dte) -- check for time is within 10 secs ) select category = c1.category, startdate = case when c1.f = 'E' then dateadd(S, 1, c1.dte) else c1.dte end, enddate = case when c2.f = 'S' then dateadd(s, -1, c2.dte) else c2.dte end from cte3 c1 inner join cte3 c2 on c1.category = c2.category and c1.row_no = c2.row_no - 1 /* category startdate enddate ----------- ------------------------ ------------------------ 10 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 10 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-01-01 17:49:59.000 2010-05-03 17:49:58.000 11 2010-05-03 17:49:59.000 2010-10-30 17:49:59.000 11 2010-10-30 17:50:00.000 2011-10-30 17:49:59.000 (5 row(s) affected) */
4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

itzpriya21 avatar image itzpriya21 commented ·
Thanks. But if the difference is more than 10 secs, it will fail. Is there any other way?
0 Likes 0 ·
Squirrel avatar image Squirrel commented ·
what do you mean exactly ? If the diff is more than 10 secs, then do you want to split it ? What is your criteria ? You can adjust it accordingly in in "dateadd(second, -10, c2.dte)"
0 Likes 0 ·
itzpriya21 avatar image itzpriya21 commented ·
Thanks Squirrel. The end time for category 10 is 10 seconds higher in the second row. The overlapped period of 1/1/2010 to 05/03/2010 got separated and created as a new record. By comparing the 2 records for category 10, the second row ends 10 seconds higher and that row becomes latest now. So, for the 10 secods no need to have a new group. In some situations that can be 20 secods too... The criteria is for category 10 on a give time period it should return one record only. Hope this helps. I am sorry, I didn't give full picture before.
0 Likes 0 ·
Squirrel avatar image Squirrel commented ·
so what is the criteria that you want want to combine or split ?
0 Likes 0 ·
ThomasRushton avatar image
ThomasRushton answered
Depending on your rules for date boundary validity, it may be possible for you to get the right results by changing the CTE as follows: with cte as ( select category, dte = convert(datetime, convert(varchar(16), startdate, 120)), f = 'S' from @tbl union select category, dte = convert(datetime, convert(varchar(16), enddate, 120)) f = 'E' from @tbl ) This will change the dates so that it only goes down to minutes - seconds are ignored.
1 comment
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

itzpriya21 avatar image itzpriya21 commented ·
Thanks Thomas for your quick answer. But, seconds can't be ignored in this case. For category 10 it has overlaps. But the later one has 10 seconds longer. So, there is no need to split that into 2 rows. It can be kept as it is and the overlapped one can only be separated....
0 Likes 0 ·
Fatherjack avatar image
Fatherjack answered
@itspriya21 - can you try adding extra information as comments or by editing your original question please? It will help people new to the question to catch up on your details and offer some help to you. Thanks
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.