0

据我了解,使用游标dynamic将反映对基表所做的任何更改。为什么在以下示例中不会出现这种情况?

我用一个表变量和一个具有相同结果的实际表尝试了这个。如果循环开始后的行@@fetch_status未注释,我会得到我期望的结果。

declare @BalanceTable table
(
    LineId int not null identity(1, 1),
    Qty int not null,
    Price   money not null
)

insert into @BalanceTable (Qty, Price) values (3000, 1)
insert into @BalanceTable (Qty, Price) values (40, 2)
insert into @BalanceTable (Qty, Price) values (1, 1)
insert into @BalanceTable (Qty, Price) values (2000, 1)
insert into @BalanceTable (Qty, Price) values (4047, 2)
insert into @BalanceTable (Qty, Price) values (-3000, 1)
insert into @BalanceTable (Qty, Price) values (-38, 2)
insert into @BalanceTable (Qty, Price) values (3000, 1)

declare BalanceTable cursor
  dynamic for
    select LineId, Qty, Price
      from @BalanceTable
      order by LineId

declare @LineId int
declare @Qty int
declare @Price money

open BalanceTable

fetch next from BalanceTable into @LineId, @Qty, @Price

while @@fetch_status = 0
begin
    -- select @Qty = Qty, @Price = Price from @BalanceTable where LineId = @LineId

    declare @SearchLessZero bit
    set @SearchLessZero = case when @Qty > 0 then 1 else 0 end

    declare @OffsetLineId int
    declare @OffsetQty int
    set @OffsetLineId = -1

    while @Qty > 0 and @OffsetLineId is not null
    begin
        select @OffsetLineId = min(LineId)
          from @BalanceTable
          where LineId > @LineId and Price = @Price and 
            ((@SearchLessZero = 1 and Qty < 0) or (@SearchLessZero = 0 and Qty > 0))

        if @OffsetLineId is not null
        begin
            select @OffsetQty = Qty
              from @BalanceTable
              where LineId = @OffsetLineId

            if @Qty > -@OffsetQty
            begin
                set @Qty = @Qty + @OffsetQty
                set @OffsetQty = 0
            end
            else
            begin
                set @OffsetQty = @OffsetQty + @Qty
                set @Qty = 0
            end

            update @BalanceTable set Qty = @OffsetQty where LineId =     @OffsetLineId
        end
    end

    update @BalanceTable set Qty = @Qty where LineId = @LineId

    fetch next from BalanceTable into @LineId, @Qty, @Price
end

close BalanceTable
deallocate BalanceTable

select *
  from @BalanceTable
  order by LineId
4

1 回答 1

3

动态游标中只允许很少的执行计划运算符。如果游标查询的执行计划包含不允许的运算符,则游标将转换为快照游标,因此看不到更新。

如果您查看光标的执行计划,您会发现发生了这种情况: 不是动态游标

查询中的问题运算符是排序。删除它,您将看到更新。

如果需要对数据进行排序,请向表中添加聚集索引,这样ORDER BY就不需要排序运算符。

于 2013-01-09T02:27:53.633 回答