需要返回每个位置每天的所有可用时间段



我想了解如何将示例 1 中的下表"汇总"到累积可用时间段中,如示例 2 所示。
以下代码按天和半小时时间段返回所有可用位置及其空闲时间。

我需要以周期为单位返回可用时间。 例如,如果某个位置在上午 9 点至下午 5 点之间可用,则应显示。

返回数据的代码:

SELECT 
LTB.CalendarDate, 
LTB.VenueCode, 
LTB.VenueName, 
LTB.LocationCode, 
LTB.LocationDescription, 
LTB.OpenTime, 
LTB.CloseTime, 
LTB.Weekday, 
LTB.WeekdayName, 
LTB.MaxUniqueParticipants, 
LTB.TimeStartBlock, 
LTB.TimeEndBlock
FROM
--LTB
--TimeBlock
(
SELECT              LocationsOpenClose.CalendarDate,
LocationsOpenClose.StartTime, 
LocationsOpenClose.EndTime, 
LocationsOpenClose.VenueCode, 
LocationsOpenClose.VenueName, 
LocationsOpenClose.LocationCode, 
LocationsOpenClose.LocationDescription, 
LocationsOpenClose.Weekday, 
LocationsOpenClose.WeekdayName,
LocationsOpenClose.MaxUniqueParticipants, 
LocationsOpenClose.OpenTime, 
LocationsOpenClose.CloseTime,
TimeDimension_2.[Time] AS TimeStartBlock, 
DATEADD(SECOND, 1799, TimeDimension_2.[Time])
AS TimeEndBlock
--Locations Open Close
FROM            (SELECT        
dbo.LocationRoster.CalendarDate, 
dbo.LocationRoster.StartTime, 
dbo.LocationRoster.EndTime, 
dbo.Venues.VenueCode, 
dbo.Venues.VenueName, 
dbo.Locations.LocationCode, 
dbo.Locations.Description AS LocationDescription, 
DateDimension.Weekday, 
DateDimension.WeekdayName, 
dbo.Locations.MaxUniqueParticipants,
TimeDimension.[Time] AS OpenTime, 
TimeDimension_1.[Time] AS CloseTime
FROM      dbo.LocationRoster 
INNER JOIN dbo.Locations ON dbo.LocationRoster.LocationGUID = dbo.Locations.LocationGUID 
INNER JOIN DateDimension ON dbo.LocationRoster.CalendarDate = DateDimension.[Date] 
INNER JOIN TimeDimension ON dbo.LocationRoster.StartTime = TimeDimension.MinuteFromMidnight 
INNER JOIN TimeDimension TimeDimension_1 ON dbo.LocationRoster.EndTime = TimeDimension_1.MinuteFromMidnight 
INNER JOIN dbo.Venues ON dbo.Locations.VenueGUID = dbo.Venues.VenueGUID) AS LocationsOpenClose 
RIGHT OUTER JOIN  TimeDimension TimeDimension_2 ON TimeDimension_2.[Time] BETWEEN LocationsOpenClose.OpenTime AND DATEADD(SECOND, -1, LocationsOpenClose.CloseTime)
WHERE (LocationsOpenClose.CalendarDate BETWEEN '2018/08/15' AND '2018/08/16') ) AS LTB 
--CETB
--CalendarEntriesStartFinish
LEFT OUTER JOIN
(
SELECT        
CalendarEntriesStartFinish.CalendarEntryDate, 
CalendarEntriesStartFinish.VenueCode, 
CalendarEntriesStartFinish.VenueName, 
CalendarEntriesStartFinish.LocationCode, 
CalendarEntriesStartFinish.LocationDescription, 
CalendarEntriesStartFinish.BookingStartTime, 
CalendarEntriesStartFinish.BookingEndTime, 
TimeDimension_2.[Time] AS TimeStartBlock, 
DATEADD(SECOND, -1, TimeDimension_2.[Time]) AS TimeEndBlock,
CalendarEntriesStartFinish.ReferenceGUID

FROM            
(
SELECT       
CONVERT(DATE, dbo.CalendarEntries.StartDateTime) AS CalendarEntryDate, 
dbo.Venues.VenueCode, 
dbo.Venues.VenueName, 
dbo.Locations.LocationCode, 
dbo.Locations.Description AS LocationDescription, 
CONVERT(TIME, dbo.CalendarEntries.StartDateTime) AS BookingStartTime, 
DATEADD(SECOND,-1,CONVERT(TIME, dbo.CalendarEntries.FinishDateTime)) AS BookingEndTime,
dbo.CalendarEntries.ReferenceGUID
FROM    dbo.CalendarEntries 
INNER JOIN dbo.Locations ON dbo.CalendarEntries.LocationGUID = dbo.Locations.LocationGUID 
INNER JOIN dbo.Venues ON dbo.Locations.VenueGUID = dbo.Venues.VenueGUID
WHERE (dbo.CalendarEntries.CalendarEntryType IN (0, 2)) AND (dbo.Locations.IsScheduled = 1)
) AS  CalendarEntriesStartFinish 
RIGHT OUTER JOIN TimeDimension TimeDimension_2 ON TimeDimension_2.[Time] BETWEEN CalendarEntriesStartFinish.BookingStartTime AND CalendarEntriesStartFinish.BookingEndTime
WHERE (CalendarEntriesStartFinish.CalendarEntryDate BETWEEN '2018/08/15' AND '2018/08/16')
) AS CETB ON LTB.CalendarDate = CONVERT(DATE,CETB.CalendarEntryDate) AND LTB.LocationCode = CETB.LocationCode AND LTB.TimeStartBlock = CETB.TimeStartBlock 

WHERE (CETB.CalendarEntryDate IS NULL)
ORDER BY LTB.CalendarDate, LTB.LocationDescription, LTB.TimeStartBlock 

示例 1:当前结果

CalendarDate    VenueCode   VenueName   LocationCode    LocationDescription OpenTime    CloseTime   Weekday WeekdayName MaxUniqueParticipants   TimeStartBlock  TimeEndBlock
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  08:30:00    08:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  09:00:00    09:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  11:00:00    11:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  11:30:00    11:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  12:00:00    12:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  12:30:00    12:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  16:00:00    16:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  16:30:00    16:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  17:00:00    17:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  17:30:00    17:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  18:00:00    18:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  18:30:00    18:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  19:00:00    19:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  19:30:00    19:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  20:00:00    20:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  20:30:00    20:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  21:00:00    21:29:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  21:30:00    21:59:59

上面显示了半小时的所有可用时间。 它显示 A 位置在 8 月 15 日的 13:00 至 16:00 不可用。

示例 2:所需结果

CalendarDate    VenueCode   VenueName   LocationCode    LocationDescription OpenTime    CloseTime   Weekday WeekdayName MaxUniqueParticipants   TimeStartBlock  TimeEndBlock
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  08:30:00    12:59:59
15/08/2018  VC  Venue Name  Lcode    A Location     05:30:00    22:00:00    4   Wednesday   20  16:00:00    21:59:59

以便他们知道 A 位置在 05:30 和 08:30 之间免费,然后在 16:00 到 22:00 之间再次免费

时间维度表以半小时为间隔进行拆分。

一位同事在下面建议,但我无法让它工作。

WITH t AS (
SELECT LTB.CalendarDate d,ROW_NUMBER() OVER(ORDER BY LTB.CalendarDate) i
FROM @d
GROUP BY LTB.CalendarDate
)
SELECT MIN(d),MAX(d)
FROM t
GROUP BY DATEDIFF(day,i,d)

我的SQL并不惊人,所以请进行完整的解释,感谢您的帮助。

这里有一个例子,用我自己的测试数据

--build some sample data
select * into #tempt from 
(
SELECT cast('20180515' as date) calendardate,  'VC' as VenueCode, CAST('08:30:00' as time) opentime, CAST('08:59:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VC' as VenueCode, CAST('09:00:00' as time) opentime, CAST('09:29:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VC' as VenueCode, CAST('09:30:00' as time) opentime, CAST('15:59:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VC' as VenueCode, CAST('16:30:00' as time) opentime, CAST('18:30:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VX' as VenueCode, CAST('08:30:00' as time) opentime, CAST('08:59:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VX' as VenueCode, CAST('09:00:00' as time) opentime, CAST('09:29:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VX' as VenueCode, CAST('09:45:00' as time) opentime, CAST('15:59:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VX' as VenueCode, CAST('16:45:00' as time) opentime, CAST('18:30:59' as time) closetime union
SELECT cast('20180515' as date) calendardate,  'VX' as VenueCode, CAST('18:31:00' as time) opentime, CAST('22:30:59' as time) closetime

) dq
--now do the work
--build a 'seconds in day' table using the first 3 CTE tables, 
;with secs as (select 0 sc union all select sc + 1 from secs where sc < 59),
hrs as (select 0 hr union all select hr + 1 from hrs where hr < 23),
allt as (select dateadd(SECOND, s1.sc + m1.sc * 60 + h1.hr * 3600, CAST('00:00:00' as time)) t from secs s1, secs m1, hrs h1),
island as (select SQ.VenueCode,allt.t, case when exists(select 0 from #tempt tm WHERE SQ.VenueCode = tm.VenueCode and allt.t BETWEEN tm.opentime and tm.closetime) then 1 else 0 end x from allt cross join (SELECT distinct t3.VenueCode FROM  #tempt t3) SQ),    --calculation starts here
calc as (select VenueCode,t,x,ROW_NUMBER() over(partition by venuecode order by t) - ROW_NUMBER() over(partition by venuecode,x order by t) z    from island)              --asigns a number to all in an island
select VenueCode,x,MIN(t),MAX(t) from calc group by VenueCode, x,z having x = 1 order by venuecode, MIN(t)                                --summarises islands


--clear test data
drop table #tempt;

最新更新