2013-06-19 26 views
1

我正在爲我們公司的筆記本電腦刷新編寫預訂系統。我需要能夠計算出哪幾天有可用插槽,並返回他們在一個日曆控件來呈現(即,如果每天有可用天數是可選的,否則不使用c#和SQL檢查日期範圍的最有效方法

的邏輯如下:

  • 技術人員可以建立每天3檯筆記本電腦。
  • 在任何一天都有可能是可用的1,2或3的技術人員。
  • 的表將舉行的預訂已經取得

每天可用的時隙總數(以僞代碼):

((laptops per day) * (technicians available)) - slots already booked 

我的問題是,什麼是獲得這種最有效的方法是什麼?我想最好在SQL端完成,並帶有一個函數來返回帶有可用插槽的日期表。 (只要至少有一個插槽可用,這並不重要。)

到目前爲止,我可以把所有這一切都歸功於我。我堅持的是,我不想有一個所有可能的日期表,因爲它似乎有點低效。我希望能夠做的是有效地迭代現在到未來3個月之間的一系列日期,並從那裏計算可用日期。

我可以在c#中做到這一點,但它會讓我覺得效率低下,因爲它將不得不在每個可能的日子裏繼續敲擊SQL服務器。似乎最好在SQL方面做,但我不知道如何以這種方式迭代可能的日期。

解決方案到目前爲止

使用@克里斯的方法,我可以得到一個日期範圍,其中插槽書沒有一組超過最大:

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次預訂。下一步是添加技術人員可用性!

+0

對於日期範圍,你在看'實際日期還是TimeSpan' – MethodMan

+0

我猜的實際日期。假設我從7月1日到10月1日的範圍內,我想迭代每個日期(從7月1日開始),並檢查是否有可用的插槽。如果是這樣,請將它添加到表中以返回 - 如果沒有,則不要。我想要的最終結果基本上只是一個包含單個(日期)列的日期列表,其中仍有可用的插槽。 – Ben

+1

你真的認爲效率會很重要嗎?也許你應該考慮更多更容易編寫和維護的代碼類型? –

回答

2

這個回答解決了說,這個問題的一部分:「什麼我希望能夠做的是有效地迭代現在和未來3個月之間的一系列日期,並從那裏計算可用日期。「

如果您使用的是MSSQL,那麼CTE可能會有所幫助。要dynammically生成日期範圍如下所示的代碼可用於:

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 

這最後SELECT之後可以加入到你的其他表來獲取DAT該日期,執行計算等

然而,這不一定是做到這一點的最佳方式。假設你有一些方法可以獲得每天有多少工程師免費的清單,那麼就不需要重複其他任何日期(因爲你知道那些日期沒有可用性)。所以爲此類似:

SELECT count(1), Date 
From EngineerWorkDays 
GROUP BY Date 
Where Date>= Getdate() 
and Date < DATEADD(m,3,Getdate()) 

會返回有可能完成工作的日期列表。另一個選擇,以獲得已分配的工作,然後將給你所有你需要的數據。在c#中的顯示代碼中,您可以每天迭代並檢查數據集中的任何相關數據(無論工程師是否可用,有多少人,已預訂了多少工作等)。

不要忘記,如果這是一個共享的應用程序來檢查預訂之前是否還有空間,以防別人在您完成初始查詢後預訂了某些內容。

+0

乾杯@Chris - 任何想法我可以如何接近下一個位:http://stackoverflow.com/questions/17212299/most-efficient-way-to-check-a-range-of-dates-using-c-sharp -and-sql-part-2 – Ben

+0

看起來你已經排序了。 :) – Chris

1

試試這個:

Select [DatesAvailable] From TableName 
Where [DatesAvailable] Between BeginningDate And DateAdd(m, 3, BeginningDate) And 
     SlotsAvailable > 0 

這應該給你,有可用於在未來3個月內槽的任何日期...

+0

這種情況下'dateavailable'表是什麼? Ben遇到的問題是他不想在所有可能的日期中都有一張桌子,我相信...... – Chris

+0

DatesAvailable是Ben桌子中的一個字段..「我想最好在SQL方面完成,具有返回帶有可用插槽的日期表的功能(只要至少有一個插槽可用,則無關緊要)。「 – Dustin

+0

是的,所以他的問題是關於如何獲得該表具有可用插槽的日期,而不是如何過濾該表格。並且爲第一條評論缺乏清晰性而表示歉意,我的意思是「TableName」。 – Chris

0

下面是做這件事:

DECLARE @iToday As INT; SET @iToday = CAST(GetDate() As INT); 
DECLARE @iDays As INT; SET @iDays = 90; 

WITH cte_0to9 As 
(
    Select 0 As Num UNION ALL Select 1 UNION ALL Select 2 UNION ALL Select 3 
    UNION ALL Select 4 UNION ALL Select 5 UNION ALL Select 6 UNION ALL Select 7 
    UNION ALL Select 8 UNION ALL Select 9 
) 
, cte_0to99 As 
(
    SELECT (Tens.Num * 10) + Ones.Num As Num 
    FROM  cte_0to9 As Ones 
    CROSS JOIN cte_0to9 As Tens 
) 
, cteDays As 
(
    SELECT CAST(@iToday + Num As DATETIME) As PossibleDate 
    FROM cte_0to99 
    WHERE Num <= @iDays 
) 
, cteTechnicianUtilization As 
(
    SELECT t.Technician, 
      d.PossibleDate, 
      (Select COUNT(*) From Bookings b 
      Where b.Technician = t.Technician 
       And b.BookDate = d.PossibleDate) As SlotsUsed 
    FROM Technicians As t 
    CROSS JOIN cteDays d 
) 
SELECT PossibleDate, SUM(Util-3) As TotalAvailableSlots 
FROM cteTechnicianUtilization 
WHERE Util < 3 
GROUP BY PossibleDate 
HAVING SUM(Util-3) > 0 

注意,這種方法,而較長(代碼明智)是比使用遞歸更有效。

+0

注:更新/更正 – RBarryYoung

+0

效率更高?我在遞歸中使用的方法在管理工作室中運行得非常快,我無法想象在選擇三個月的併發日期時您會發現任何實際的好處。你有沒有關於效率的基準?我主要問,因爲代碼讓我覺得它比較難讀,所以效率問題對我來說是非常重要的,因爲我希望這樣做(並且我應該注意我相信它可能是,我只想知道多少)。 – Chris

+0

@Chris下面是一篇文章,詳細測量它:http://www.sqlservercentral.com/articles/T-SQL/74118/ – RBarryYoung