随机调度

时间:2010-07-19 13:53:13

标签: sql sql-server stored-procedures

我的数据库中有以下表格:

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。

如果需要插入多个记录,则计划的时间不应超过一小时。

感谢任何和所有帮助!

2 个答案:

答案 0 :(得分: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

就实际插入记录的代码而言,我需要更多地了解数据库中的表。

答案 1 :(得分:1)

这是我对你要做的事情的最好猜测。 CTE的前两部分实际上只是为了让事情变成类似于FlyingStreudel建议的形式。理想情况下,您应该更改数据库以匹配该格式,而不是通过CTE执行此操作。这将使这更加简单,并且对数据完整性也更好。

接下来,我以小时为单位获得不同的开始时间。如果你不能使用CTE(你没有提到你正在使用的SQL Server版本),你可以通过加入Numbers表来实现这一点。

最后,我使用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