0

我正在使用一个日程表,办公室在早上有约会,然后在午餐时被封锁,然后在下午有更多的约会。该办公室正在寻求根据已有的开始和结束时间即时更改其预约频率和数量的能力。

例如:如果办公室在10-12点每 60 分钟有一次约会,从 12-1 午餐和下午 1-3 点约会,那么日程表将如下所示

Day         Time                IsBlocked   EndTime
2013-07-01  10:00:00.0000000    0           NULL
2013-07-01  11:00:00.0000000    0           NULL
2013-07-01  12:00:00.0000000    1           13:00:00.0000000
2013-07-01  13:00:00.0000000    0           NULL
2013-07-01  14:00:00.0000000    0           NULL

假设他们想将那一天的约会更改为每半小时(30 分钟)2 次约会, 他们可以调用存储过程

ChangeAppointmentFrequency(@day = '7/1/2013', @intervalInMinutes = 30, @numberOfAppointmentsInTheInterval = 2)

它将在新插槽中插入新约会,并保持任何现有约会不变。

  Day           Time      IsBlocked EndTime
2013-07-01  10:00:00.0000000    0   NULL
2013-07-01  10:00:00.0000000    0   NULL
2013-07-01  10:30:00.0000000    0   NULL
2013-07-01  10:30:00.0000000    0   NULL
2013-07-01  11:00:00.0000000    0   NULL
2013-07-01  11:00:00.0000000    0   NULL
2013-07-01  11:30:00.0000000    0   NULL
2013-07-01  11:30:00.0000000    0   NULL
2013-07-01  12:00:00.0000000    1   13:00:00.0000000
2013-07-01  13:00:00.0000000    0   NULL
2013-07-01  13:00:00.0000000    0   NULL
2013-07-01  13:30:00.0000000    0   NULL
2013-07-01  13:30:00.0000000    0   NULL
2013-07-01  14:00:00.0000000    0   NULL
2013-07-01  14:00:00.0000000    0   NULL
2013-07-01  14:30:00.0000000    0   NULL
2013-07-01  14:30:00.0000000    0   NULL

我很难在不使用游标的情况下雄辩地找到开始和结束日期谢谢

初始表

CREATE TABLE Schedule([Day] DATE,[Time] TIME, IsBlocked bit, EndTime TIME);
insert into Schedule ([Day], [Time], IsBlocked, EndTime) values 
('7/1/2013', '10:00:00', 0, null),
('7/1/2013', '11:00:00', 0, null),
('7/1/2013', '12:00:00', 1, '13:00:00'),
('7/1/2013', '13:00:00', 0, null),
('7/1/2013', '14:00:00', 0, null)
4

3 回答 3

1

假设您的回答是约会不能重叠,我会这样处理这个问题。

根据您对时间段持续时间的(新)定义以及办公室在早上打开(当然也关闭)的时间,为工作日中的每个时间段创建一个包含开始和结束时间的 CTE。

然后从该 CTE 插入到您现有的约会表中,如果不存在任何约会(或午餐时段),其开始时间或结束时间将介于您的 CTE 时段的开始时间和结束时间之间。

PS 当只给出/定义约会持续时间时,您必须计算结束时间。开始时间以办公室的开放时间为准。

于 2013-06-23T17:09:32.150 回答
1

您的目标尚不清楚,但我不确定您的设计是否有解决方案。

您的约会表中没有主键,这会立即引发警告标志。从实际的角度来看,您无法知道要配对哪些记录。如果并行约会开始时间相互抵消怎么办?

例如,假设一组约会开始于一个小时和半小时,另一组约会开始于 1/4 和 3/4 小时。您的模型中没有任何内容可以证明这一点。它可以很容易地解释为每 1/4 小时开始的一系列 15 分钟的约会。

如果您想要平行的不同轨道,那么您需要某种标识符来区分轨道。轨道 ID 可以代表会议室、主持人或更抽象的东西。

我还建议在每个约会行中都有开始和停止时间。你为什么要假设在一个约会的结束和下一个约会的开始之间没有间隔?

于 2013-06-23T17:09:44.510 回答
0

我能够使用 AMtimes 和 PMTimes 的 CTE 完成此操作

IF EXISTS (SELECT * FROM sys.procedures WHERE Name = 'InsertAppointmentDay' AND [type_desc] = 'SQL_STORED_PROCEDURE')
    DROP PROCEDURE InsertAppointmentDay;
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[InsertAppointmentDay]
    @BACCode char(6)  
    ,@Division varchar(10)
    ,@ScheduleDate date
    ,@StartTime1 time(7)
    ,@EndTime1 time(7)
    ,@StartTime2 time(7)
    ,@EndTime2 time(7)   
    ,@TimeZoneAbbreviation char(6)   
AS
BEGIN  
    DECLARE @IntervalMinutes INT 
    DECLARE @AppointmentsPerInterval INT 
    DECLARE @ErrorMessage NVARCHAR(4000) ;
    DECLARE @ErrorState INT  ;

    -- make sure the dealer does not already have records in the schedule table for that day. We want to make sure if you already have appointments for that day 
    if   exists  (select Id from Schedule where   DealerDivision = @Division and DealerBACCode = @BACCode and AppointmentDay = @ScheduleDate)
    begin
        set @ErrorMessage = 'a record already exist in schedule table with DealerDivision = '+@Division+' and DealerBACCode = '+@BACCode+' and AppointmentDay = '+CAST(@ScheduleDate as varchar(20)); 
        RAISERROR (@ErrorMessage,  16,  @ErrorState );
        Return;
    end 

    BEGIN TRY 
        BEGIN TRANSACTION 
            DECLARE @ZipOffset char(6);

            SELECT @ZipOffset = [TimeZoneOffset]  FROM [TimeZone]   WHERE [TimeZoneAbbreviation] = @TimeZoneAbbreviation;

            -- find out from the frequency table how many minutes are in the interval and how many appointments per interval. look it up by FrequencyCode in the Frequency table 
            select @IntervalMinutes = IntervalMinutes, @AppointmentsPerInterval= AppointmentsPerInterval 
                from   Frequency where Code = (select top 1 AppointmentCode from Dealer where  Division = @Division and BACCode = @BACCode) 


            -- @Intervals table is a temp table with all the possiable timeslots we will add (a morning section and an afternoon section)
            -- example. if the location is open from 10:00 to 11:00 lunch then 13:00 to 15:00 the and the interval is 60 minutes you will get
            -- 10:00   
            -- 11:00 
            -- 13:00
            -- 14:00
            -- 15:00 
            DECLARE @Intervals table    (   [Time] TIME   UNIQUE ([Time])) 

            if (@StartTime2 is null)
            begin
                ;WITH AmSlots([TimeSlot] ) AS 
                ( 
                        SELECT @StartTime1   UNION ALL 
                        SELECT 
                        [TimeSlot] = DATEADD(mi, @IntervalMinutes, [TimeSlot]) 
                        FROM AmSlots WHERE DATEADD(mi, @IntervalMinutes, [TimeSlot]) <=  @EndTime1
                ) 
                insert into @Intervals select [TimeSlot] from [AmSlots]  
            end
            else 
            begin
                print 'pm times'
                ;WITH AmSlots([TimeSlot] ) AS 
                ( 
                        SELECT @StartTime1   UNION ALL 
                        SELECT 
                        [TimeSlot] = DATEADD(mi, @IntervalMinutes, [TimeSlot]) 
                        FROM AmSlots WHERE DATEADD(mi, @IntervalMinutes, [TimeSlot]) <=  @EndTime1
                ) ,PmSlots([TimeSlot] ) AS 
                (  
                        SELECT @StartTime2    UNION ALL
                        SELECT 
                        [TimeSlot] = DATEADD(mi, @IntervalMinutes, [TimeSlot])  
                        FROM PmSlots WHERE DATEADD(mi, @IntervalMinutes, [TimeSlot]) <=  @EndTime2  
                ) 
                insert into @Intervals select [TimeSlot] from [AmSlots] union all select [TimeSlot] from [PmSlots] 
            end


            -- @DayAppointments is a table to store the combination of time slots with the Number of appointments per interval
            -- example if the location is open from 10:00 to 11:00 lunch then 13:00 to 14:00 the and the interval = 60 minutes and the AppointmentsPerInterval = 3 you will get
            -- 1 | 10:00   
            -- 2 | 10:00   
            -- 3 | 10:00   
            -- 1 | 11:00   
            -- 2 | 11:00   
            -- 3 | 11:00   
            -- 1 | 13:00   
            -- 2 | 13:00   
            -- 3 | 13:00   
            -- 1 | 14:00   
            -- 2 | 14:00   
            -- 3 | 14:00   
            DECLARE @DayAppointments TABLE 
            (
                [AppointmentNumberForTimeSlot] INT,
                [Time] TIME
                UNIQUE ([AppointmentNumberForTimeSlot],[Time])
            )
            -- Quanity is a sequence table (if @AppointmentsPerInterval = 3   Quanity will contain  1, 2, 3) used to cross join with @Intervals to get the @DayAppointments
            ;WITH Quanity([AppointmentNumberForTimeSlot] ) AS
            (
                    SELECT 1 UNION ALL
                    SELECT  [AppointmentNumberForTimeSlot] = [AppointmentNumberForTimeSlot] + 1  FROM Quanity WHERE [AppointmentNumberForTimeSlot]  <   @AppointmentsPerInterval
            ) 
            insert into @DayAppointments select [AppointmentNumberForTimeSlot], [Time] from Quanity cross join @Intervals 

            --select * from  @DayAppointments   

            -- insert one record into Schedule for each record in @DayAppointments 
            INSERT INTO [Schedule]  ([DealerBACCode],[DealerDivision],[AppointmentDay],[AppointmentTime], [ZipOffset], [TimeZoneAbbreviation], [ModifiedBy])
                select  @BACCode , @Division ,@ScheduleDate ,[Time]  , @ZipOffset , @TimeZoneAbbreviation , 'InsertAppointmentDay' from  @DayAppointments  where [Time] IS NOT NULL 
            print 'about to compelte transaction'
         COMMIT TRANSACTION
    END TRY
    BEGIN CATCH 
        print 'about to Rollback transaction'
        Rollback Transaction  
        set @ErrorMessage  = ERROR_MESSAGE()
        set @ErrorState   = ERROR_STATE() 
        RAISERROR (@ErrorMessage, 16, @ErrorState);
        Return;
    END CATCH;  
END 
于 2013-08-24T13:27:29.903 回答