继昨天提出的问题之后,我需要为笔记本电脑推出“预订系统”返回一系列“可用”日期。我想通过检查每个日期可能的总插槽数,并减去已经预订的插槽数来填充用户可以预订插槽的可用日期表。
逻辑如下:
相关表格是:
tl_sb_slotBooking 这包含已经预订的
tl_sb_availabilityPeriods 这用于计算给定日期的可用插槽总数
我可以带回一个固定最大数量(在这种情况下为3)的插槽日期列表:
DECLARE @startDate DATE
DECLARE @endDate DATE
SET @startDate = GETDATE()
SET @endDate = DATEADD(m,3,@startDate)
;
WITH dates(Date) AS
(
SELECT @startdate as Date
UNION ALL
SELECT DATEADD(d,1,[Date])
FROM dates
WHERE DATE < @enddate
)
SELECT Date
FROM dates
EXCEPT
SELECT date
FROM tl_sb_booking
GROUP BY date
HAVING COUNT(date) >= 3
但是,最大值并不总是3,每天都会更改。
我可以找到给定日期的最大可能插槽:
DECLARE @myDate DATETIME = '2013-06-22'
SELECT SUM(laptopsPerDay) AS totalSlots
FROM tl_sb_technicianAvailability
WHERE startDate <= @myDate AND endDate >= @myDate
AND availabiltyStateID=3
它将带回6作为2013-06-22可用的插槽总数。 (availabilityStateID字段用于存储可用/不可用等。)
所以,我坚持的一点是将两者结合起来。
我想要的是每个可能的日期,如果已经预订的插槽数量少于当天可能的插槽数量,请将其添加到要返回的表格中(否则不要)。
答案 0 :(得分:2)
首先,虽然你只是生成一个小列表using a CTE to generate a sequential list performs terribly,但最好避免使用。
为此,我将使用系统表Master..spt_values
作为序列号的列表,但如果您担心使用未记录的系统表,那么上面的链接中还有其他方法。
我要做的第一件事就是将技术人员的可用日期分成每天一行,这样就可以让技术人员只需要部分的peiod(例如,如果你想查询,可以从表格中获取)从6月18日到6月26日,没有任何技术人员使用您发布的查询显示为可用:
SELECT Date = DATEADD(DAY, spt.Number, ta.StartDate),
ta.TechnicianID,
ta.LapTopsPerDay
FROM tl_sb_technicianAvailability ta
INNER JOIN Master..spt_values spt
ON spt.Type = 'P'
AND spt.Number BETWEEN 0 AND DATEDIFF(DAY, ta.startDate, ta.EndDate)
This would simply turn:
TechnicianID StartDate EndDate LapTopsPerDay
1 20130620 20130624 3
到
Date TechnicianID LapTopsPerDay
20130620 1 3
20130621 1 3
20130622 1 3
20130623 1 3
20130624 1 3
然后,您可以将此列表限制为所需的日期范围,并总结笔记本电脑的总数,因为在技术级别上不需要这样做:
WITH ExplodedAvailability AS
( SELECT Date = DATEADD(DAY, spt.Number, ta.StartDate),
ta.TechnicianID,
ta.LapTopsPerDay
FROM tl_sb_technicianAvailability ta
INNER JOIN Master..spt_values spt
ON spt.Type = 'P'
AND spt.Number BETWEEN 0 AND DATEDIFF(DAY, ta.startDate, ta.EndDate)
)
SELECT Date, TotalLaptops = SUM(LapTopsPerDay)
FROM ExplodedAvailability
WHERE Date >= @StartDate
AND Date < @EndDate
GROUP BY Date;
最后,您可以将LEFT JOIN连接到预订表以获取每日可用的插槽
WITH ExplodedAvailability AS
( SELECT Date = DATEADD(DAY, spt.Number, ta.StartDate),
ta.TechnicianID,
ta.LapTopsPerDay
FROM tl_sb_technicianAvailability ta
INNER JOIN Master..spt_values spt
ON spt.Type = 'P'
AND spt.Number BETWEEN 0 AND DATEDIFF(DAY, ta.startDate, ta.EndDate)
), Availability AS
( SELECT Date, TotalLaptops = SUM(LapTopsPerDay)
FROM ExplodedAvailability
WHERE Date >= @StartDate
AND Date < @EndDate
GROUP BY Date
), Bookings AS
( SELECT Date, SlotsBooked = COUNT(*)
FROM tl_sb_booking
GROUP BY Date
)
SELECT Availability.Date,
Availability.TotalLaptops,
RemainingSlots = Availability.TotalLaptops - ISNULL(Bookings.SlotsBooked, 0)
FROM Availability
LEFT JOIN Bookings
ON Bookings.Date = Availability.Date;
我认为您所追求的是在下一个可用日期添加预订,因此执行此操作的查询将是:
DECLARE @UserID INT = 1;
WITH ExplodedAvailability AS
( SELECT Date = DATEADD(DAY, spt.Number, ta.StartDate),
ta.TechnicianID,
ta.LapTopsPerDay
FROM tl_sb_technicianAvailability ta
INNER JOIN Master..spt_values spt
ON spt.Type = 'P'
AND spt.Number BETWEEN 0 AND DATEDIFF(DAY, ta.startDate, ta.EndDate)
), Availability AS
( SELECT Date, TotalLaptops = SUM(LapTopsPerDay)
FROM ExplodedAvailability
WHERE Date >= CAST(GETDATE() AS DATE)
GROUP BY Date
), Bookings AS
( SELECT Date, SlotsBooked = COUNT(*)
FROM tl_sb_booking
GROUP BY Date
)
INSERT tl_sb_slotBooking (UserID, Date)
SELECT @UserID, MIN(Availability.Date)
FROM Availability
LEFT JOIN Bookings
ON Bookings.Date = Availability.Date
WHERE Availability.TotalLaptops > ISNULL(Bookings.SlotsBooked, 0)
答案 1 :(得分:0)
这应该对任何人都有用,这是我最终做到的方式:
DECLARE @startDate DATE
DECLARE @endDate DATE
SET @startDate = GETDATE()
SET @endDate = DATEADD(m,3,@startDate)
;
WITH dates(currentDate) AS
(
SELECT @startdate as currentDate
UNION ALL
SELECT DATEADD(d,1,[currentDate])
FROM dates
WHERE currentDate < @enddate
)
SELECT currentDate
FROM dates
WHERE /* slots booked for date */
(
SELECT count([date])
FROM tl_sb_booking
where [date] = currentDate
)
<
/* total slots available */
(
SELECT SUM(laptopsPerDay) AS totalSlots
FROM tl_sb_technicianAvailability
WHERE startDate <= currentDate AND endDate >= currentDate
AND availabiltyStateID=3
)