我想了解如何将示例1中的下表“汇总”到累积的可用时间段,如示例2中所示。 以下代码按天和半小时时隙返回所有可用的位置及其空闲时间。
我需要按时段返回可用时间。 EG,如果应该显示上午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
上面显示了所有可用时间(半小时)。它显示了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并不令人惊讶,因此请提供完整的解释,感谢您的帮助。
答案 0 :(得分:0)
这是一个示例,其中包含我自己的测试数据
--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;