2013-06-20 137 views
3

繼我昨天提出的問題後,我需要爲筆記本電腦部署「預約系統」返回一系列「可用」日期。我想通過檢查每個日期的可能的總時隙數量,並且減去已經預訂的時隙數量,來填充用戶可以預約時隙的可能日期表格。在SQL中檢查日期範圍

的邏輯如下:

  • 技術人員可以構建每天3級的筆記本電腦。
  • 在任何一天,可能有1,2或3位技術人員可用。
  • 表持有的訂單做出
  • 我不希望所有可能的日期表,我想計算它的飛行

相關的表是:

tl_sb_slotBooking 這包含已預訂的訂單

enter image description here

tl_sb_availabilityPeriods 這是用於計算在某一天 enter image description here

我可以帶回具有固定最大數目日期的列表(在這種情況下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年6月22日的總時隙數。 (availabilityStateID字段用於存儲可用/不可用等)

所以,我堅持的位是兩者結合。

我想要的是對於每個可能的日期,如果已經預訂的插槽數少於當天可能的插槽數,請將其添加到正在返回的表中(否則不要)。

回答

2

首先,雖然您只生成一個小列表,但最好避免使用using a CTE to generate a sequential list performs terribly

爲了這個目的,我將使用系統表Master..spt_values作爲數字的順序列表,但如果您擔心使用未記錄的系統表,那麼在上面的鏈接中還有其他方法。

我會做的第一件事情是將技術人員的可用日期分成每天一排,這將允許技術人員只需要一部分所需的技術人員(例如,從上表中你sceen鏡頭,如果你想從6月18日查詢到技術人員6月26日無SHOW將使用您已發佈的查詢)顯示爲可供選擇:

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 

然後,您可以限制此列表所需的日期範圍,並總結了總的筆記本電腦比可以爲這是沒有必要在technicial層面開展:

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) 
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 
         )