The need for date validation overlaps or not in sql server

Below is the input code

ID  EMP_ID       PROJECT_NAME            START_DATE          END_DATE
1   10016351    ABC                       22-12-2016        15-05-2017
2   10016351    ABC                       01-09-2016        22-11-2016
1   10081503    RTBS AMaaS                21-11-2016        15-02-2017
2   10081503    RTBS AMaaS                18-07-2016        25-11-2016
3   10081503    RTBS AMaaS                21-08-2016        13-10-2016
4   10081503    RTBS AMaaS                03-02-2015        22-05-2015
1   10089293    RTBS PDaaS                17-02-2017        31-12-2017
2   10089293    RTBS PDaaS                13-06-2016        14-02-2017

      

I need to check an employee if the dates overlap or not. If so, it will return the min. Start date and Max. End date and flag as "O".

For example, for emp_id = 10081503, dates overlap 21-11-2016. Falls from 18 to 201 and 25-11-2016. 21-08-2016 - between 18-07-2016 and 25-11-2016 so the query should return a start date of 07/18/2016 (min) and an end date as 02/15/2017 (max) for dates that overlap. For rest records, it must return the same record with the "N" flag.

EMP_ID | PROJECT_NAME | START_DATE | END_DATE | Flag of 10081503 | RTBS AMaaS | 21-11-2016 | 15-02-2017 | About 10081503 | RTBS AMaaS | 03-02-2015 | 22-05-2015 | N

Like my final conclusion,

ID  EMP_ID       PROJECT_NAME            START_DATE          END_DATE   FLAG
1   10016351    ABC                       22-12-2016        15-05-2017   N
2   10016351    ABC                       01-09-2016        22-11-2016   N
1    10081503   RTBS AMaaS                21-11-2016        15-02-2017   O
2    10081503   RTBS AMaaS                03-02-2015        22-05-2015   N
1   10089293    RTBS PDaaS                17-02-2017        31-12-2017   N
2   10089293    RTBS PDaaS                13-06-2016        14-02-2017   N

      

+3


source to share


3 answers


Use outer apply()

to return the first one id

to overlap and group by this value. Using row_number()

to renumber id

:

select
    id = row_number() over (
      partition by t.emp_id 
      order by min(start_date) desc
      )
  , t.emp_id
  , t.project_name
  , start_date = min(start_date)
  , end_date   = max(end_date)
  , flag = max(case when x.id <> t.id then 'O' else 'N' end)
from t
  outer apply (
    select top 1 i.id
    from t i
    where i.Emp_Id = t.Emp_id
      and i.End_Date > t.Start_Date
      and t.End_Date > i.Start_Date
    order by i.Start_Date
      ) x
group by t.emp_id, t.project_name, x.id

      

Demo version of the rexter: http://rextester.com/VHMZ91714

returns:

+----+----------+--------------+------------+------------+------+
| id |  emp_id  | project_name | start_date |  end_date  | flag |
+----+----------+--------------+------------+------------+------+
|  1 | 10016351 | ABC          | 2016-12-22 | 2017-05-15 | N    |
|  2 | 10016351 | ABC          | 2016-09-01 | 2016-11-22 | N    |
|  1 | 10081503 | RTBS AMaaS   | 2016-07-18 | 2017-02-15 | O    |
|  2 | 10081503 | RTBS AMaaS   | 2015-02-03 | 2015-05-22 | N    |
|  1 | 10089293 | RTBS PDaaS   | 2017-02-17 | 2017-12-31 | N    |
|  2 | 10089293 | RTBS PDaaS   | 2016-06-13 | 2017-02-14 | N    |
+----+----------+--------------+------------+------------+------+

      


The above will cause the overlapping ranges to be flattened, but if you need to collapse multiple ranges that only overlap at the edges into one range, we can use a calendar or dates table like this:

For just 152KB in memory, you can have 30 year dates in your table with this:



/* dates table */
declare @fromdate date = '20000101';
declare @years    int  = 30;
/* 30 years, 19 used data pages ~152kb in memory, ~264kb on disk */
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
select top (datediff(day, @fromdate,dateadd(year,@years,@fromdate)))
    [Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
into dbo.Dates
from n as deka cross join n as hecto cross join n as kilo
               cross join n as tenK  cross join n as hundredK
order by [Date];
create unique clustered index ix_dbo_Dates_date on dbo.Dates([Date]);

      

If you don't want to create a date table, you can use this query to create dates like this:

declare @fromdate date = '20100101';
declare @thrudate date = getdate();
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
  select top (datediff(day, @fromdate, @thrudate)+1) 
      [Date]=convert(date,dateadd(day,row_number() over(order by (select 1))-1,@fromdate))
  from n as deka cross join n as hecto cross join n as kilo
                cross join n as tenK cross join n as hundredK
   order by [Date]
)
, cte as (
  select
      t.emp_id
    , t.project_name
    , d.date
    , rn = row_number() over (partition by t.emp_id, t.project_name order by d.date)-1
    , flag = case when count(*) > 1 then 'O' else 'N' end  
  from t
    inner join dates d
      on d.date >= t.start_date
     and d.date <= t.end_date
  group by t.emp_id, t.project_name, d.date
)
select 
    id = row_number() over (partition by emp_id order by min(date) desc)
  , emp_id
  , project_name
  , start_date = min(date)
  , end_date = max(date)
  , flag = max(flag)
from cte
group by emp_id, project_name, dateadd(day,-rn,date)

      

registry: http://rextester.com/QKEMH32326

returns:

+----+----------+--------------+------------+------------+------+
| id |  emp_id  | project_name | start_date |  end_date  | flag |
+----+----------+--------------+------------+------------+------+
|  1 | 10016351 | ABC          | 2016-12-22 | 2017-05-15 | N    |
|  2 | 10016351 | ABC          | 2016-09-01 | 2016-11-22 | N    |
|  1 | 10081503 | RTBS AMaaS   | 2016-07-18 | 2017-02-15 | O    |
|  2 | 10081503 | RTBS AMaaS   | 2015-02-03 | 2015-05-22 | N    |
|  1 | 10089293 | RTBS PDaaS   | 2017-02-17 | 2017-12-31 | N    |
|  2 | 10089293 | RTBS PDaaS   | 2016-06-13 | 2017-02-14 | N    |
+----+----------+--------------+------------+------------+------+

      

directory of calendar and table numbers:

+1


source


Thanks everyone for the help.!

Need help in the same context,

Followed the script below, enter image description here



In such a scenario, we end up with two records in DISTRIBUTION DETAILS. This is because the resource was assigned to two different projects, but the placement end date of the first distribution project (in the example above) overlaps with the distribution start date of the second distribution project. So to calculate the validity period of allocation 1: Stay period (Alloc 1) = Start date Alloc (Alloc 2) - Start date Alloc (Alloc 1) i.e. (17-11-2016) - (01-09-2016) = 77 The calculation of the validity period for allocation 2 has not changed. Here, the final entry will look like this:

[1]: https://i.stack.imgur.com/DSkjd.jpg

0


source


Unfortunately this first solution does not work as stated, executing the code will only result in three lines (the code groups even non-overlapping dates):

id  emp_id  start_date  end_date    flag
1   10016351    2016-09-01  2017-05-15  O
1   10081503    2015-02-03  2017-02-15  O
1   10089293    2016-06-13  2017-12-31  O

      

Can anyone provide a working solution? Below is some sample code that will work without creating any tables, just for testing:

declare @t table  (id int, emp_id int, project_name char(10), start_date date, end_date date, flag char)

insert into @t
values
(1 ,  10016351 ,   'ABC       ',                '2016-12-22'  ,      '2017-05-15','X'),
(2 ,  10016351 ,   'ABC       ',                '2016-09-01'  ,      '2016-11-22','X'),
(1 ,  10081503 ,   'RTBS AMaaS',                '2016-11-21'  ,      '2017-02-15','X'),
(2 ,  10081503 ,   'RTBS AMaaS',                '2016-07-18'  ,      '2016-11-25','X'),
(3 ,  10081503 ,   'RTBS AMaaS',                '2016-08-21'  ,      '2016-10-13','X'),
(4 ,  10081503 ,   'RTBS AMaaS',                '2015-02-03'  ,      '2015-05-22','X'),
(1 ,  10089293 ,   'RTBS PDaaS',                '2017-02-17'  ,      '2017-12-31','X'),
(2 ,  10089293 ,   'RTBS PDaaS',                '2016-06-13'  ,      '2017-02-14','X')

select
    id = row_number() over (
      partition by emp_id 
      order by min(start_date) desc
      )
  , emp_id
  , start_date = min(start_date)
  , end_date   = max(end_date)
  , flag = max(case when x.id <> t.id then 'O' else 'N' end)
from @t t
  outer apply (
    select top 1 i.id
    from @t i
    where i.Emp_Id = Emp_id
      and i.End_Date > Start_Date
      and End_Date > i.Start_Date
    order by i.Start_Date
      ) x
group by emp_id,  x.id

      

0


source







All Articles