有关SQL中游标的错误

时间:2009-04-18 06:20:55

标签: sql sql-server sql-server-2005 tsql cursors

以下是我的存储过程。它包含一个子查询

 Select StartTime From DrTimings Where DrID = @DrID 

如果此子查询返回多个值,则会出错。子查询返回多行。我想在游标中获取每个@StartTime和@EndTime。意思是我想“从Doctor获取下一个@StTime和@EndTime”

我可以在游标中使用两个参数吗?

ALTER PROCEDURE [dbo].SP_AFK_GetSlotsByDate
    @DrID int,
    @AppointmentDate Datetime 
AS
BEGIN

Declare @StartTime Datetime
Declare @EndTime Datetime
BEGIN
    SET @StartTime = (Select StartTime From DrTimings Where DrID = @DrID)
    SET @EndTime =  (Select EndTime From DrTimings Where DrID = @DrID)
END

DECLARE Doctor CURSOR FOR

Select StartTime  from  TimeList1 where StartTime>=@StartTime and StartTime<@EndTime

Declare @StTime datetime
Declare @SlotID int
Declare @AppointmentTime datetime

Declare @TempSlots Table (SlotID int , AppointmentTime datetime null) 


Insert into
@TempSlots
(
SlotID ,
AppointmentTime
)
values(
0,
Getdate()
)

open Doctor
    fetch next from Doctor into @StTime
        while @@fetch_status = 0
            Begin

Select  @SlotID= T.SlotId from TimeList1 T
where T.StartTime>=@StartTime and T.StartTime<@EndTime and
T.SlotId not in 
        (Select A.SlotId from AppointmentSheet A where A.AppointmentDate=@AppointmentDate)

Select @AppointmentTime = Convert(varchar,right(T.StartTime,7),131)+' - '+ Convert(varchar,right(T.EndTime,7),131) 
from TimeList1 T
where T.StartTime>=@StartTime and T.StartTime<@EndTime and
T.SlotId not in 
        (Select A.SlotId from AppointmentSheet A where A.AppointmentDate=@AppointmentDate)

        Update @TempSlots
        Set SlotID  = @SlotID,
                AppointmentTime=@AppointmentTime

    fetch next from Doctor into @StTime
           end
    close Doctor
    deallocate Doctor

    Select * From @TempSlots
END 

2 个答案:

答案 0 :(得分:1)

只需以这种方式添加下一个变量:

fetch next from Doctor into @StTime, @EndTime

光标的select语句应包含EndTime:

select StartTime, EndTime 
from   TimeList1 
where  StartTime>=@StartTime and StartTime<@EndTime

答案 1 :(得分:1)

虽然游标是迭代结果集的简单方法,但由于性能影响,它们推荐。

如果我知道 TimeList1 表的结构以及它与DrTimings表的关系,我建议使用使用游标的版本。

但是,在审核了您的T-SQL之后,我决定为您提供一个更新版本,以减少冗余并使用JOINS而不是子查询:

ALTER PROCEDURE [dbo].SP_AFK_GetSlotsByDate
(
    @DrID int,
    @AppointmentDate DateTime 
)
AS

DECLARE 
    @StartTime DateTime,
    @EndTime DateTime,
    @SlotID int,
    @AppointmentTime DateTime;

-- Retrieve the initial values for StartTime and EndTime
-- These values get overwritten by the cursor (?)
SELECT 
    @StartTime = StartTime,
    @EndTime = EndTime
FROM
    DrTimings
WHERE
    DrID = @DrID;


DECLARE @TempSlots TABLE
(
    SlotID int, 
    AppointmentTime datetime NULL
); 

-- Set default values
INSERT @TempSlots (SlotID,AppointmentTime)
VALUES (0, GETDATE());


DECLARE Doctor CURSOR FOR
SELECT 
    StartTime,
    EndTime  
FROM  
    TimeList1 
where 
    StartTime >= @StartTime AND 
    StartTime < @EndTime;

OPEN Doctor
FETCH NEXT FROM Doctor INTO @StartTime,@EndTime
WHILE @@FETCH_STATUS = 0
    BEGIN
        SELECT
            @SlotID = T.SlotId, 
            @AppointmentTime = CONVERT(varchar,RIGHT(T.StartTime,7),131)
                               + ' - ' + CONVERT(varchar,RIGHT(T.EndTime,7),131) 
        FROM 
            TimeList1 T
            LEFT JOIN AppointmentSheet A ON T.SlotId = A.SlotId
        WHERE 
            T.StartTime >= @StartTime AND 
            T.StartTime < @EndTime AND
            A.AppointmentDate = @AppointmentDate AND
            A.SlotId IS NULL;

        -- This table will always be updated to contain the latest values
        -- it will contain only one row
        UPDATE 
            @TempSlots
        SET
            SlotID  = @SlotID,
            AppointmentTime = @AppointmentTime;

        FETCH NEXT FROM Doctor INTO @StartTime,@EndTime
    END

CLOSE Doctor
DEALLOCATE Doctor

-- Return results
SELECT 
    SlotId,
    AppointmentTime
FROM 
    @TempSlots;

更新:如果目的是获取SlotId和AppointmentTime的最新值,则甚至不需要迭代。