2010-07-19 78 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