一天缺少时间范围

时间:2012-08-01 12:09:29

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

我有一张这样的表:

create table time_sheet
(
      StatusCode char(1),
      start_time datetime,
      end_time datetime
)

insert into time_sheet values
('W','2012-08-01 10:00:00','2012-08-01 12:00:00'),
('D','2012-08-01 12:00:00','2012-08-01 14:00:00'),
('N','2012-08-01 16:00:00','2012-08-01 18:00:00')

输出应该是这样的:

StatusCode start_time               end_time
B          2012-08-01 08:00:00.000  2012-08-01 10:00:00.000
W          2012-08-01 10:00:00.000  2012-08-01 12:00:00.000
D          2012-08-01 12:00:00.000  2012-08-01 14:00:00.000
B          2012-08-01 14:00:00.000  2012-08-01 16:00:00.000
N          2012-08-01 16:00:00.000  2012-08-01 18:00:00.000
B          2012-08-01 18:00:00.000  2012-08-01 20:00:00.000

一天的结束和结束声明如下。

declare @begingOfDay datetime='2012-08-01 08:00:00.000'
declare @endOfDay    datetime='2012-08-01 20:00:00.000'

基本上我希望在 begingOfDay endOfDay 之间的结果集中缺少时间范围记录,其中statusCode B 。请注意,在输出中有3条记录添加了StatusCode B

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:1)

您的示例数据(注意,T已添加到字符串中以强制执行明确的日期转换):

create table time_sheet
(
      StatusCode char(1),
      start_time datetime,
      end_time datetime
)

insert into time_sheet values
('W','2012-08-01T10:00:00','2012-08-01T12:00:00'),
('D','2012-08-01T12:00:00','2012-08-01T14:00:00'),
('N','2012-08-01T16:00:00','2012-08-01T18:00:00')

declare @begingOfDay datetime='2012-08-01T08:00:00.000'
declare @endOfDay    datetime='2012-08-01T20:00:00.000'

查询:

;with AllDTs as (
    select @begingOfDay as TimePoint
    union
    select @endOfDay
    union
    select start_time from time_sheet
    union
    select end_time from time_sheet
), OrderedDTs as (
    select TimePoint,ROW_NUMBER() OVER (ORDER BY TimePoint) as rn
    from AllDTs
), Periods as (
    select o1.TimePoint as start_time,o2.TimePoint as end_time
    from
        OrderedDTs o1
            inner join
        OrderedDTs o2
            on
                o1.rn = o2.rn-1
)
select
    COALESCE(ts.StatusCode,'B') as StatusCode,
    p.start_time,
    p.end_time
from
    Periods p
        left join
    time_sheet ts
        on
            p.start_time = ts.start_time and
            p.end_time = ts.end_time

结果:

StatusCode start_time              end_time
---------- ----------------------- -----------------------
B          2012-08-01 08:00:00.000 2012-08-01 10:00:00.000
W          2012-08-01 10:00:00.000 2012-08-01 12:00:00.000
D          2012-08-01 12:00:00.000 2012-08-01 14:00:00.000
B          2012-08-01 14:00:00.000 2012-08-01 16:00:00.000
N          2012-08-01 16:00:00.000 2012-08-01 18:00:00.000
B          2012-08-01 18:00:00.000 2012-08-01 20:00:00.000

注意,我假设原始表中没有重叠的时间段。第一个CTE(AllDTs)只找到我们感兴趣的所有唯一日期时间值。 OrderedDTsPeriods比将所有这些日期时间值安排到连续的时间段中。然后,最终查询将获取每个句点,并尝试将它们与原始表匹配,如果可能的话。如果没有,那么显然是B期。