CURSOR в SQL запускается несколько раз, если в нем только 1 запись - PullRequest
0 голосов
/ 27 мая 2020

У меня проблема с КУРСОРОМ, когда в некоторых случаях он заполняется только одним значением, но вместо того, чтобы сразу существовать, он продолжается и продолжается до тех пор, пока в моем случае не произойдет сбой.

Это код :

            DECLARE @positionID as INT
            DECLARE position_cursor CURSOR FOR 
            SELECT  positionUniqueNumber 
            FROM  position
            WHERE position.EmployeeID = @EmployeeID

            OPEN position_cursor  
            FETCH NEXT FROM position_cursor INTO @positionID  

            WHILE @@FETCH_STATUS = 0  
            BEGIN  
                    UPDATE   position
                    SET  positionFromDate = DATEADD(day,@days, positionFromDate)
                    WHERE position.positionUniqueNumber = @positionID

                  FETCH NEXT FROM position_cursor INTO @positionID 
            END 

            CLOSE position_cursor  
            DEALLOCATE position_cursor

Я бы ожидал, что курсор будет существовать после одного запуска, если 'position_cursor' имеет только одно значение, вместо этого он продолжается и продолжается, пока он не попытается установить Date выше 9999, и он выйдет из строя. Для меня обходной путь - проверить, сколько записей в таблице соответствует критериям, и использовать курсор, только если их больше 1, но я хотел бы найти лучший способ. Мысли? Спасибо

1 Ответ

1 голос
/ 27 мая 2020

Вот репродукция с закомментированным исправлением. Большинство людей ожидают семантики STATI C для курсора, но это не значение по умолчанию. Если ваше обновление приводит к перемещению строки в индексе, читаемом курсором, он может прочитать одну и ту же строку дважды.

Просто всегда объявляйте ваши курсоры как LOCAL STATI C, чтобы избежать этих проблем.

drop table if exists position
go
create table position(positionuniquenumber int primary key nonclustered, EmployeeId int, positionFromDate DateTime)
create unique clustered index cix_position on position(employeeid,positionFromDate,positionuniquenumber)

insert into position(positionuniquenumber,EmployeeId,positionFromDate) values (1,1,getdate())
go
DECLARE @EmployeeID int = 1
declare @Days int = 1
DECLARE @positionID as INT
DECLARE position_cursor CURSOR /*LOCAL STATIC*/ FOR 
SELECT  positionUniqueNumber 
FROM  position
WHERE position.EmployeeID = @EmployeeID

OPEN position_cursor  
FETCH NEXT FROM position_cursor INTO @positionID  

WHILE @@FETCH_STATUS = 0  
BEGIN  
        UPDATE   position
        SET  positionFromDate = DATEADD(day,@days, positionFromDate)
        WHERE position.positionUniqueNumber = @positionID

        FETCH NEXT FROM position_cursor INTO @positionID 
END 

CLOSE position_cursor  
DEALLOCATE position_cursor
...