SQL检查某些时隙之间是否发生时间

时间:2017-01-06 15:05:51

标签: sql sql-server

我有一张约会表(见下文)

ID | Start Time | End Time |
1  | 09:00      | 09:45    |
2  | 10:15      | 10:30    |

我想要做的是输出一个表格,显示每条记录是否占用15分钟的时间段。所以上面的表格会输出如下:

09:00 - 09:15 | 09:16 - 09:30 | 09:31 - 09:45 | 09:46 - 10:00 | 10:01 - 10:15 | 10:16 - 10:30
ID 1          | ID 1          | ID 1          |               | ID 2          | ID 2

关于从哪里开始的任何想法?!

修改

这是我要去的地方,只是没有尝试包括结束时间或者如何在开始和结束时间跨越的时间段,例如在09:16 - 09:30示例中的ID 1:

SELECT 
'09:00 - 09:15' = case when 
cast(a_start as time) >= '09:00:00' and cast(a_start as time) < '09:16:00'
then a_id else '' END,

'09:16 - 09:30' = case when 
cast(a_start as time) >= '09:16:00' and cast(a_start as time) < '09:30:00'
then a_id else '' END,

'09:31 - 09:45' = case when 
cast(a_start as time) >= '09:31:00' and cast(a_start as time) < '09:45:00'
then a_id else '' END,     

'09:46 - 10:00' = case when 
cast(a_start as time) >= '09:46:00' and cast(a_start as time) < '10:00:00'
then a_idelse '' END 

  FROM appointments

编辑2:

现在有点工作:

SELECT 

    '08:00 - 08:59' = case when 
    (cast(a_start as time) <= '08:00:00') 
    AND 
    (cast(a_end as time) >= '08:59:00')
    then a_id else '' END,

    '09:00 - 09:15' = case when 
    (cast(a_start as time) <= '09:00:00') 
    AND 
    (cast(a_end as time) >= '09:15:00')
    then a_id else '' END,

    '09:16 - 09:30' = case when 
    (cast(a_start as time) <= '09:16:00') 
    AND 
    (cast(a_end as time) >= '09:30:00')
    then a_id else '' END,

    '09:31 - 09:45' = case when 
    (cast(a_start as time) <= '09:31:00') 
    AND 
    (cast(a_end as time) >= '09:45:00')
    then a_id else '' END,     

    '09:46 - 10:00' = case when 
    (cast(a_start as time) <= '09:46:00') 
    AND 
    (cast(a_end as time) >= '10:00:00')
    then a_id else '' END,

    '10:01 - 10:15' = case when 
    (cast(a_start as time) <= '10:01:00') 
    AND 
    (cast(a_end as time) >= '10:15:00')
    then a_id else '' END 


      FROM appointments

2 个答案:

答案 0 :(得分:1)

您可以使用某些日期数学和交叉表(也称为条件聚合)来执行此操作。我还使用了一个计数器来根据表中的数据生成时隙。你可以根据需要调整它。就个人而言,我在我的系统中保留了一个计数表作为视图。这是超级疯狂的快速零读取。

create View [dbo].[cteTally] as

WITH
    E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
    E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
    E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
    cteTally(N) AS 
    (
        SELECT  ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
    )
select N from cteTally

现在我们需要实际的ddl来使用。

if OBJECT_ID('tempdb..#Appt') is not null
    drop table #Appt

create table #Appt
(
    ID int
    , StartTime time
    , EndTime time
)
insert #Appt select 1, '09:00', '09:45';
insert #Appt select 2, '10:15', '10:30';

要实际解决问题,我首先生成时间段,然后将约会数据加入时隙,以确定将哪个约会(如果有)分配到该时间段。

这可能需要稍微调整以满足您的确切要求,但这应该非常接近。

with TimeSlots as
(
    select TimeSlot = dateadd(minute, (t.N) * 15, '09:00') --should make the start time dynamic
    from cteTally t
    where t.N <=
    (
        select datediff(minute, MIN(StartTime), MAX(EndTime)) / 15
        from #Appt
    )
)
, Appointments as
(
    select *
        , ROW_NUMBER() over(order by ts.TimeSlot) as RowNum
    from TimeSlots ts
    left join #Appt a on convert(datetime, ts.TimeSlot) >= convert(datetime, a.StartTime) 
        AND convert(datetime, ts.TimeSlot) <= convert(datetime, a.EndTime)
)

select MAX(case when RowNum = 1 then ID end) as '09:00 - 09:15'
    , MAX(case when RowNum = 2 then ID end) as '09:16 - 09:30'
    , MAX(case when RowNum = 3 then ID end) as '09:31 - 09:45'
    , MAX(case when RowNum = 4 then ID end) as '09:46 - 10:00'
    , MAX(case when RowNum = 5 then ID end) as '10:01 - 10:15'
    , MAX(case when RowNum = 6 then ID end) as '10:16 - 10:30'
from Appointments

答案 1 :(得分:1)

这是一个动态支点。

我通过将临时结果放到#temp中来作弊,但如果需要可以更改。我还添加了一个DATE作为第一列(很容易删除)

--Drop Table #Temp

Declare @TimeR1 time = '09:00'
Declare @TimeR2 time = '17:00'

Select Date = cast([Start Time] as date)
      ,Val  = concat('ID ',B.ID)
      ,Col  = Format(cast(A.TR1 as datetime),'HH:mm') +' - ' + Format(cast(A.TR2 as datetime),'HH:mm')
Into  #Temp
From (Select Top 96 
             TR1=cast(DateAdd(MINUTE,(15*(Row_Number() Over (Order By (Select null))-1))+1,'1900-01-01') as time)
            ,TR2=cast(DateAdd(MINUTE,(15*(Row_Number() Over (Order By (Select null))+0))+0,'1900-01-01') as time)
      From master..spt_values 
     ) A
Left Join YourTable B 
  on TR1 between cast([Start Time] as time)  and cast([End Time] as time) or TR2 between cast([Start Time ] as time) and cast([End Time] as time)
Where TR1 >=@TimeR1 and TR1<@TimeR2


Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(Col) From #Temp  Order by 1 For XML Path('')),1,1,'') 
Select  @SQL = '
Select [Date],' + @SQL + '
From (Select * From #Temp Where Date is not null
      Union All
      Select Date,Val,Col
        From (Select Distinct Date,Val='''' from #Temp Where Date is not Null) A
        Cross Join (Select Distinct Col From #Temp) B
) A
Pivot (max(Val) For [Col] in (' + @SQL + ') ) p'
Exec(@SQL);

返回 enter image description here

**图像被剔除......它实际上是17:00