SQL筛选器日期范围查询

时间:2014-02-22 15:29:45

标签: sql sql-server sql-server-2008 sql-server-2008-r2

我有一份日程记录列表

StaffSchedules

enter image description here

其中一些人已经预订了。

BookedSchedules

enter image description here

还有一些假期

假日

enter image description here

我想只获得可用的员工时间表

Expected Schedules= StaffSchedule - BookedSchedule-Holidays

即,我只想从StaffSchedule Table

获取第2,6行

以下是我尝试的查询,但没有显示结果

with NonBookingSlots as
(
select StartdateTime,EndDateTime from Holidays
union all
select StartdateTime,EndDateTime from BookedSchedules
)

SELECT
    StaffId, StartdateTime, EndDateTime
FROM StaffSchedule
WHERE 
not exists (select 1
                from NonBookingSlots h
                where cast(StartdateTime as DATETIME) between 
                cast(h.startdatetime as DATETIME) 
                and cast(h.enddatetime as DATETIME)
           )

SQL FIDDLE DEMO

2 个答案:

答案 0 :(得分:3)

对于所有示例,我假设BookedSchedules中的开始和结束时间与StaffSchedules开始和结束时间完全匹配。

使用CTE,类似于问题:

我不建议使用此查询,但它可能会有所帮助,因为它类似于问题中的查询。它不是很易读。

with NonBookingSlots as
(
  select null as StaffId,StartdateTime,EndDateTime from Holidays
  union all
  select StaffId,StartdateTime,EndDateTime from BookedSchedules
)

select
  StaffId, StartdateTime, EndDateTime
from 
  StaffSchedule
where
  not exists(
    select
      1
    from 
      NonBookingSlots
    where
      StaffSchedule.StaffId = isnull(NonBookingSlots.StaffId,StaffSchedule.StaffId)
      and (
        (
          StaffSchedule.StartDateTime =  NonBookingSlots.StartDateTime
          and StaffSchedule.EndDateTime = NonBookingSlots.EndDateTime
        ) or (
          StaffSchedule.StartDateTime <  NonBookingSlots.EndDateTime
          and StaffSchedule.EndDateTime > NonBookingSlots.StartDateTime
        )
     )
  ) 

SQL小提琴:http://sqlfiddle.com/#!3/9cbf4/14

没有CTE:

在我看来,这个版本更具可读性。

select
  StaffId, StartdateTime, EndDateTime
from 
  StaffSchedule
where
  not exists(
    select
      1
    from 
      BookedSchedules
    where
      StaffSchedule.StaffId = BookedSchedules.StaffId
      and StaffSchedule.StartDateTime =  BookedSchedules.StartDateTime
      and StaffSchedule.EndDateTime = BookedSchedules.EndDateTime
  ) and not exists(
    select
      1
    from 
      Holidays
    where
      StaffSchedule.StartDateTime <  Holidays.EndDateTime
      and StaffSchedule.EndDateTime > Holidays.StartDateTime
  )

SQL小提琴:http://sqlfiddle.com/#!3/9cbf4/15

使用外键 - 我建议:

如果BookedSchedules始终与StaffSchedule匹配,则应使用StaffSchedule的外键,而不是在BookedSchedules中复制开始和结束时间。这样可以实现更清晰,更有效的查询。

select
  StaffId, StartdateTime, EndDateTime
from 
  StaffSchedule
where
  not exists(
    select
      1
    from 
      BookedSchedules
    where
      StaffSchedule.Id = BookedSchedules.StaffScheduleId
  ) and not exists(
    select
      1
    from 
      Holidays
    where
      StaffSchedule.StartDateTime <=  Holidays.EndDateTime
      and StaffSchedule.EndDateTime >= Holidays.StartDateTime
  )

SQL小提琴:http://sqlfiddle.com/#!3/8a684/3

答案 1 :(得分:1)

select *
  from dbo.StaffSchedule x
 where not exists (select 'y'
          from dbo.BookedSchedules y
         where y.staffid = x.staffid
           and y.startdatetime = x.startdatetime
           and y.enddatetime = x.enddatetime)
   and not exists (select 'z'
          from dbo.Holidays z
         where cast(z.startdatetime as date) =
               cast(x.startdatetime as date))

SQL小提琴:http://sqlfiddle.com/#!3/07698/19/0

编辑 - 处理超过一天的假期:

select *
  from dbo.StaffSchedule x
 where not exists (select 'y'
          from dbo.BookedSchedules y
         where y.staffid = x.staffid
           and y.startdatetime = x.startdatetime
           and y.enddatetime = x.enddatetime)
   and not exists (select 'z'
          from dbo.Holidays z
         where cast(z.startdatetime as date) <=
               cast(x.startdatetime as date)
           and cast(z.enddatetime as date) >=
               cast(x.enddatetime as date))