Ошибка относительно курсора в SQL - PullRequest
1 голос
/ 18 апреля 2009

следующая моя хранимая процедура. Содержит подзапрос

 Select StartTime From DrTimings Where DrID = @DrID 

Если этот подзапрос возвращает более одного значения, я получаю сообщение об ошибке. Подзапрос возвращает несколько строк. Я хочу получить каждый @StartTime и @EndTime в курсоре. Означает, что я хочу "получить следующий от Доктора в @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 ]

1 голос
/ 18 апреля 2009

Хотя курсоры - это простой способ перебора набора результатов, они не рекомендуются из-за влияния на производительность.

Если бы я знал структуру вашей таблицы 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, то итерация даже не требуется.

1 голос
/ 18 апреля 2009

Просто добавьте следующую переменную следующим образом:

fetch next from Doctor into @StTime, @EndTime

Оператор select вашего курсора должен содержать столбец EndTime:

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