累計。 UPDATE 一時テーブルと CTE の比較
create table Test( OrderID int primary key, Qty int not null);declare @i int =1;while @i <=5000 begin insert into Test(OrderID, Qty) 値 (@i * 2,ランド () * 10); set @i =@i + 1;end;
プレ>再帰的ソリューション 9 秒かかります:
with T AS( select ROW_NUMBER() over(OrderID による順序) as rn, * from test),R(Rn, OrderId, Qty, RunningTotal) as( select Rn, OrderID, Qty, Qty from tここで、rn =1 union all select t.Rn, t.OrderId, t.Qty, p.RunningTotal + t.Qty from t t join r p on t.rn =p.rn + 1)select R.OrderId, R.Qty, R.RunningTotal from roption(maxrecursion 0);
プレ>UPDATE テーブル 0 秒かかります:
create function TestRunningTotal()returns @ReturnTable table( OrderId int, Qty int, RunningTotal int)as begin insert into @ReturnTable(OrderID, Qty, RunningTotal) select OrderID, Qty, 0 from Test order by OrderID; @RunningTotal int =0 を宣言します。 update @ReturnTable set RunningTotal =@RunningTotal、@RunningTotal =@RunningTotal + Qty; return;end;
プレ>これら 2 つのアプローチは、少なくともクエリを構築するためのフレームワークを提供します。
ところで、SQL Server では、MySQL とは異なり、変数の割り当ての順序は重要ではありません。これ:
update @ReturnTable set RunningTotal =@RunningTotal, @RunningTotal =@RunningTotal + Qty;
プレ>そして以下:
update @ReturnTable set @RunningTotal =@RunningTotal + Qty, RunningTotal =@RunningTotal; コード> プレ>
どちらも同じ方法で実行されます。つまり、ステートメント内の変数の割り当ての位置に関係なく、変数の割り当てが最初に行われます。両方のクエリの出力は同じです:
OrderId Qty RunningTotal----------- ----------- ------------2 4 44 8 126 4 168 5 2110 3 2412 8 3214 2 3416 9 4318 1 4420 2 4622 0 4624 2 4826 6 54 プレ>
正確なテーブルで、買い/売りを検出するだけで、それぞれに1と-1を掛けるか、フィールドに署名するだけです。 :
update @ReturnTable set @RunningTotal =@RunningTotal + CASE WHEN BuySell ='Buy' THEN Qty ELSE -Qty END, RunningTotal =@RunningTotal; コード> プレ>
SQL Server 2012 にアップグレードする場合は、現在の合計を簡単に実装できます:
RunningTotalfrom Test として OrderID, Qty, sum(Qty) over(OrderID による順序) を選択します
プレ>正確な問題について:
select OrderID, Qty, sum(CASE WHEN BuySell ='Buy' THEN Qty ELSE -Qty END) over(OrderID による順序) as RunningTotalfrom Test;
プレ>更新
に不安がある場合風変わりな更新 、更新される行の順序が元の順序と一致するかどうかを確認するガード句を配置できます (identity(1,1) を使用):
create function TestRunningTotalGuarded() は @ReturnTable テーブル ( OrderId int, Qty int, RunningTotal int not null, RN int identity(1,1) not null) を返します @ReturnTable(OrderID, Qty, RunningTotal ) OrderID による Test order から OrderID, Qty, 0 を選択します。 @RunningTotal int =0 を宣言します。 @RN_check INT =0 を宣言します。 update @ReturnTable set @RN_check =@RN_check + 1, @RunningTotal =(RN =@RN_check の場合 @RunningTotal + Qty それ以外の場合は 1/0 end), RunningTotal =@RunningTotal; return;end;
プレ>UPDATE が実際に予測できない順序で行を更新する場合 (または何らかの可能性がある場合)、@RN_Check はもはや RN (ID 順序) と等しくなくなり、コードは ゼロ除算エラー を発生させます。 それから。ガード句を使用すると、予測不可能な更新順序が 失敗する ;これが発生した場合は、
バグを報告する時が来ました 風変わりな更新をそれほど風変わりではないものにするように Microsoft に請願します :-)本質的に命令的な操作 (変数の代入) に対する保護節ヘッジは、実際にはシーケンシャルです。