2010-07-19 83 views
2

我在我的數據庫如下表:隨機調度

TBL1
PK
客戶端ID
ScheduleDay
Time1Start
Time1Stop
Time2Start
Time2Stop
Time3Start
Time3Stop
狀態

下面是一些樣本數據

ID ClientID ScheduleDay Time1Start Time1Stop Time2Start Time2Stop Time3Start Time3Stop  
-- -------- ----------- ---------- --------- ---------- --------- ---------- --------- 
1  3  Sunday  0000  0800  1000  1300  NULL  NULL 
2  3  Monday  0000  2359  NULL  NULL  NULL  NULL 
3  3  Tuesday  1000  1200  1330  1700  1900  2200 
4  3  Wednesday 0000  0800  NULL  NULL  NULL  NULL 
5  3  Thursday 0800  1200  NULL  NULL  NULL  NULL 
6  3  Friday  0400  0800  0900  1600  NULL  NULL 

時間字段是CHAR(4)因爲我存儲在軍事格式的時間。

我需要完成的是這個;對於任何給定的ClientID,將一條或多條記錄插入日程表中,並且記錄的時間值位於tbl1的時間範圍內。例如,在週二安排ClientID 3,安排的時間可能是1120.

如果需要插入多個記錄,安排的時間應該不超過一個小時。

任何和所有幫助表示讚賞!

+0

已知哪些輸入?也就是說,ClientId知道查詢何時運行,ScheduleDay是否已知?時間應該只存在於第一對時間還是任何時間對中?它需要如何隨機?也就是說,你有什麼理由不能簡單地在開始時間加一個小時? – Thomas 2010-07-19 14:31:41

+0

而不是給出一個計劃時間的例子,如果你提供了你正在尋找的結果集,那將會更有用。否則,很難幫助你。 – 2010-07-19 14:33:27

+0

Thomas, 查詢運行時ClientID和ScheduleDay是已知的。時間可以來自任何時間,我的要求要求它足夠隨機,以至於無法預測。 Tom H, 查詢的結果將是ClientID,並且該時間屬於提供給查詢的一天中的一對時間。 – DoubleJ92 2010-07-19 14:48:12

回答

1

這是我最好的猜測,你想要做什麼。 CTE的前兩部分實際上只是把事情變成一種類似於FlyingStreudel所建議的形式。理想情況下,您應該更改數據庫以匹配該格式,而不是通過CTE執行此操作。這將使這個過程更加簡單,並且對數據完整性也更好。

接下來,我只是以小時爲單位獲得不同的開始時間。如果你不能使用CTE(你沒有提到你使用的SQL Server版本),你可以通過加入數字表來實現。

最後,我使用RAND函數和ROW_NUMBER隨機抓取其中一個開始時間。你會想爲RAND()設置一個好的種子值。

;WITH TimesAsTimes AS 
(
    SELECT 
     ScheduleDay, 
     CAST(SUBSTRING(T1.Time1Start, 1, 2) + ':' + SUBSTRING(T1.Time1Start, 3, 2) AS TIME) AS time_start, 
     CAST(SUBSTRING(T1.Time1Stop, 1, 2) + ':' + SUBSTRING(T1.Time1Stop, 3, 2) AS TIME) AS time_stop 
    FROM 
     tbl1 T1 
    WHERE 
     T1.Time1Start IS NOT NULL 
    UNION ALL 
    SELECT 
     ScheduleDay, 
     CAST(SUBSTRING(T2.Time2Start, 1, 2) + ':' + SUBSTRING(T2.Time2Start, 3, 2) AS TIME) AS time_start, 
     CAST(SUBSTRING(T2.Time2Stop, 1, 2) + ':' + SUBSTRING(T2.Time2Stop, 3, 2) AS TIME) AS time_stop 
    FROM 
     tbl1 T2 
    WHERE 
     T2.Time2Start IS NOT NULL 
    UNION ALL 
    SELECT 
     ScheduleDay, 
     CAST(SUBSTRING(T3.Time3Start, 1, 2) + ':' + SUBSTRING(T3.Time3Start, 3, 2) AS TIME) AS time_start, 
     CAST(SUBSTRING(T3.Time3Stop, 1, 2) + ':' + SUBSTRING(T3.Time3Stop, 3, 2) AS TIME) AS time_stop 
    FROM 
     tbl1 T3 
    WHERE 
     T3.Time3Start IS NOT NULL 
), 
PossibleTimeStarts AS 
(
    SELECT 
     ScheduleDay, 
     time_start, 
     time_stop 
    FROM 
     TimesAsTimes TAT 
    UNION ALL 
    SELECT 
     ScheduleDay, 
     DATEADD(hh, 1, time_start) AS time_start, 
     time_stop 
    FROM 
     PossibleTimeStarts PTS 
    WHERE 
     DATEADD(hh, 1, time_start) <= DATEADD(hh, -1, PTS.time_stop) 
), 
PossibleTimesWithRowNums AS 
(
    SELECT 
     ScheduleDay, 
     time_start, 
     ROW_NUMBER() OVER(PARTITION BY ScheduleDay ORDER BY ScheduleDay, time_start) AS row_num, 
     COUNT(*) OVER(PARTITION BY ScheduleDay) AS num_rows 
    FROM 
     PossibleTimeStarts 
) 
SELECT 
    * 
FROM 
    PossibleTimesWithRowNums 
WHERE 
    row_num = FLOOR(RAND() * num_rows) + 1 
+0

我正在使用SQL Server 2008 – DoubleJ92 2010-07-19 17:03:21

+0

然後,上面應該爲你工作,鑑於我提到的警告(正確種子RAND(),如果可以重新設計數據庫而不是使用前兩個CTE,會更好) – 2010-07-19 17:18:26

+0

這爲我做了。謝謝! – DoubleJ92 2010-07-21 20:29:02

1

首先,你可能想嘗試像

tbl_sched_avail 
PK id INT 
FK client_id INT 
day INT (1-7) 
avail_start varchar(4) 
avail_end varchar(4) 

架構這樣你不僅限於有限數量的時間圍欄的。

至於檢查的時間表可用性 - 至於對實際插入我需要更多地瞭解在數據庫中的表記錄代碼

CREATE PROCEDURE sp_ins_sched 
@start_time varchar(4), 
@end_time varchar(4), 
@client_id INT, 
@day INT 
AS 
BEGIN 

    DECLARE @can_create BIT 
    SET @can_create = 0 
    DECLARE @fence_start INT 
    DECLARE @fence_end INT 

    --IS DESIRED TIME WITHIN FENCE FOR CLIENT 
    DECLARE c CURSOR FOR 
    SELECT avail_start, avail_end FROM tbl_sched_avail 
    WHERE client_id = @client_id 
    AND day = @day 

    OPEN c 

    FETCH NEXT FROM c 
    INTO @fence_start, @fence_end 

    WHILE @@FETCH_STATUS = 0 AND @can_create = 0 
    BEGIN 
     IF @start_time >= @fence_start AND @start_time < @fence_end 
      AND @end_time > @fence_start AND <= @fence_end 
      SET @can_create = 1 

     FETCH NEXT FROM c 
     INTO @fence_start, @fence_end 
    END 

    CLOSE c 
    DEALLOCATE c 

    IF @can_create = 1 
    BEGIN 
     --insert your schedule here 
    END 

END