SQL选择日期范围内未涵盖日期的记录

时间:2016-08-25 18:57:33

标签: sql sql-server date

我无法准确得到我需要的东西。以下是我的表格示例:

Plan_ID | PlanBeginDate | PlanEndDate |
    1   |    1/1/2015   |   1/1/2016  |
    2   |    1/1/2016   |   1/1/2017  |
    3   |    1/1/2013   |   1/1/2014  |
    4   |    1/1/2015   |   1/1/2016  |

SrvID  | Srv_Plan_ID | Srv_Discipline_ID | SrvBeginDate | SrvEndDate |
  1    |      1      |        1          |   1/1/2015   |   1/1/2016 |
  2    |      1      |        3          |   1/1/2015   |   1/1/2016 |
  3    |      2      |        2          |   1/1/2016   |   4/4/2016 |
  4    |      2      |        2          |   4/5/2016   |   1/1/2017 |
  5    |      3      |        1          |   1/1/2013   |   6/1/2013 |
  6    |      3      |        2          |   1/1/2013   |   1/1/2014 |
  7    |      4      |        3          |   1/1/2015   |   7/1/2016 |
  8    |      4      |        3          |   8/1/2015   |   1/1/2016 |

我希望看到所有与其相关的每个不同学科的服务日期未涵盖日期的计划。

计划1不应出现,因为与其相关的两个学科都涵盖所有日期。

计划2不应出现,因为两个相关的服务具有相同的学科并且共同覆盖整个计划日期范围。

计划3应该出现一次,因为SrvID 5不包括整个计划日期范围。

计划4应该出现,因为7月份为纪律3发现了。

我需要一个选择语句,它将按照上述标准返回以下字段。

Plan_ID | PlanBeginDate | PlanEndDate |Srv_Discipline_ID | SrvBeginDate | SrvEndDate |

到目前为止,这就是我所拥有的。

Select Plan_ID, Srv_Discipline_ID, PlanBeginningDate, PlanEndDate, MIN(SrvBeginDate) EarliestStartDate, MAX(SrvEndDate) LatestEndDate
From dbo.Plan
JOIN Services 
    ON Plan_ID = Srv_Plan_ID
GROUP BY Plan_ID, Srv_Discipline_ID, PlanBeginDate, PlanEndDate
ORDER BY Plan_ID

1 个答案:

答案 0 :(得分:0)

我想出了一种方法,但它涉及昂贵的递归CTE,将日期范围扩展为可以加入的个别日期。所以,要明确的是,我不希望这个查询的性能非常好。

注意:我还在我使用的测试数据中将SrvEndDate的{​​{1}}值从SrvID = 7修改为7/1/2016。当你说7月份被揭露时,这一定是你的意图。

<强>设置

7/1/2015

<强>查询

create table Plans (
  Plan_ID int not null primary key,
  PlanBeginDate date not null,
  PlanEndDate date not null
)

create table Services (
  SrvID int not null primary key,
  Srv_Plan_ID int not null,
  Srv_Discipline_ID int not null,
  SrvBeginDate date not null,
  SrvEndDate date not null
)

alter table Services
add constraint Services_fk
foreign key (Srv_Plan_ID)
references Plans(Plan_ID)

insert into Plans (Plan_ID, PlanBeginDate, PlanEndDate)
values
(1, '2015-01-01', '2016-01-01'),
(2, '2016-01-01', '2017-01-01'),
(3, '2013-01-01', '2014-01-01'),
(4, '2015-01-01', '2016-01-01')

insert into Services (SrvID, Srv_Plan_ID, Srv_Discipline_ID, SrvBeginDate, SrvEndDate)
values
(1, 1, 1, '2015-01-01', '2016-01-01'),
(2, 1, 3, '2015-01-01', '2016-01-01'),
(3, 2, 2, '2016-01-01', '2016-04-04'),
(4, 2, 2, '2016-04-05', '2017-01-01'),
(5, 3, 1, '2013-01-01', '2013-06-01'),
(6, 3, 2, '2013-01-01', '2014-01-01'),
(7, 4, 3, '2015-01-01', '2015-07-01'),
(8, 4, 3, '2015-08-01', '2016-01-01')

<强>结果

with ServiceCTE as (
  select Srv_Plan_ID, Srv_Discipline_ID, SrvEndDate, SrvBeginDate as SrvDate
    from Services
   union all
  select Srv_Plan_ID, Srv_Discipline_ID, SrvEndDate, dateadd(day, 1, SrvDate) as SrvDate
    from ServiceCTE
   where SrvDate != SrvEndDate
), PlanCTE as (
  select Plan_ID, PlanEndDate, PlanBeginDate as PlanDate
    from Plans
   union all
  select Plan_ID, PlanEndDate, dateadd(day, 1, PlanDate) as PlanDate
    from PlanCTE
   where PlanDate != PlanEndDate
), UncoveredPlanDisciplineCTE as (
  select distinct pcte.Plan_ID, s.Srv_Discipline_ID
    from PlanCTE pcte
    join (select distinct Srv_Plan_ID, Srv_Discipline_ID
            from Services) s
      on s.Srv_Plan_ID = pcte.Plan_ID
   where not exists (select null
                       from ServiceCTE scte
                      where scte.Srv_Plan_ID = s.Srv_Plan_ID
                        and scte.Srv_Discipline_ID = s.Srv_Discipline_ID
                        and scte.SrvDate = pcte.PlanDate)
)
select p.Plan_ID, p.PlanBeginDate, p.PlanEndDate, 
       s.Srv_Discipline_ID, s.SrvBeginDate, s.SrvEndDate
  from UncoveredPlanDisciplineCTE c
  join Plans p
    on p.Plan_ID = c.Plan_ID
  join Services s
    on s.Srv_Plan_ID = c.Plan_ID
   and s.Srv_Discipline_ID = c.Srv_Discipline_ID
 order by p.Plan_ID, s.Srv_Discipline_ID, s.SrvBeginDate
option (maxrecursion 0)