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 に答える