根据表中的数据递归填充sql表

时间:2013-06-23 15:17:03

标签: sql sql-server tsql stored-procedures

我正在安排一张时间表,办公室在早上有约会,然后在午餐时关闭,然后在下午更多约会。该办公室正在寻找能够根据已有的开始和结束时间即时更改其约会频率和数量的能力。

例如:如果办公室预约每60分钟从10 - 12午餐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)

3 个答案:

答案 0 :(得分:1)

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

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

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

P.S。只有在给定/定义约会时间时,您必须计算结束时间。开始时间取决于办公室的开放时间。

答案 1 :(得分:1)

你的目标不明确,但我不确定你的设计是否有解决方案。

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

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

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

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

答案 2 :(得分:0)

我能够使用CTE为AMtimes和PMTimes

完成此操作
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