SQL 中的 CURSOR 在只有 1 条记录时运行多次

CURSOR in SQL runs multiple times when there is only 1 record in it

我遇到了一个 CURSOR 问题,在某些情况下,它只填充了一个值,但它并没有立即存在,而是一直持续到我的情况崩溃为止。

这是代码:

            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' 只有一个值,我希望光标在一个 运行 之后存在,而不是继续下去,直到它试图设置一个高于 9999 的日期并崩溃。 对我来说,一个解决方法是检查 table 中有多少符合条件的记录,仅当超过 1 条时才使用光标,但我想找到更好的方法。想法? 谢谢

这是一个修复被注释掉的重现。大多数人 期望 游标的 STATIC 语义,但这不是默认设置。如果您的更新导致行在游标读取的索引中移动,它可以读取同一行两次。

只需始终将游标声明为 LOCAL STATIC 即可避免这些问题。

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