2016-11-04 11 views
1

テーブル変数を使用してデータを格納するストアドプロシージャを継承し、各行を実行中の合計計算で更新します。ボリュームのレコードの順序は非常に重要です。ボリュームを最高から最低に並べる必要があります(つまり、テーブルを移動するにつれて実行中の合計がますます大きくなります)。SQL Serverテーブル変数で実行中の合計計算列を使用する

テーブル変数が更新される段階で、実行中の合計が計算されているように見えますが、テーブル変数のデータは以前にソートされていませんでした(最大音量で降順)

DECLARE @TableVariable TABLE ([ID], [Volume], [SortValue], [RunningTotal]) 

--Populate table variable and order by the sort value... 
INSERT INTO @TableVariable (ID, Volume, SortValue) 
    SELECT 
     [ID], [Volume], ABS([Volume]) as SortValue 
    FROM 
     dbo.VolumeTable 
    ORDER BY 
     SortValue DESC 

--Set TotalVolume variable... 
[email protected] = ABS(sum([Volume])) 
FROM @TableVariable 

--Calculate running total, update rows in table variable...I believe this is where problem occurs? 
SET @RunningTotal = 0 

UPDATE @TableVariable 
SET @RunningTotal = RunningTotal = @RunningTotal + [Volume] 
FROM @TableVariable 

--Output... 
SELECT 
    ID, Volume, SortValue, RunningTotal 
FROM  
    @TableVariable  
ORDER BY 
    SortValue DESC 

これは、実行中の合計が最初に計算されると予想していた最高ボリュームを持つレコード(したがって、合計= [ボリューム]を実行しています)が何らかの理由でリストのさらに下にあることになります。

Good result

しかし、ここでは、コードが実際に発生するものである:

enter image description here

ていない場合は必ず実行している合計は私が得ることを期待するものです。ここにランダム

を計算しているようですUPDATEステートメントをボリュームdescで順序付けされるようにテーブル変数に適用させる方法がありますか?今まで読んだことから、テーブル変数のソート動作に問題はあるかもしれませんが、修正方法は不明です。誰も助けることができますか?

+4

ありませんが、これを行わないことにインデックスを作成することができます。あなたは、奇妙なアップデート方法として知られているものを使用しています。これがテーブル変数であることを考えると、このテクニックに関連する既知の問題のいくつかに違反していることはすでに知っています。この作業にはクラスタ化インデックスが必要です。このテクニックについて説明しているこの記事を調べてください。 http://www.sqlservercentral.com/articles/T-SQL/68467/コメントを必ずお読みください。このアプローチは文書化されておらず、非常に議論の余地があります。 Windowsの機能はここであなたに適しています。 –

+1

[合計を実行するための最善の方法 - SQL Server 2012用に更新されました](https://sqlperformance.com/2012/07/t-sql-queries/running-totals) – GarethD

+0

イメージは両方ともボリュームの降順ソートを示し、 、私は問題が表示されません... – Zack

答えて

2

は@YourTableは実証目的でのみ使用され、明確にするために例えばSQL

で提供されるウィンドウ関数で

Declare @YourTable table (ID int,Volume int) 
Insert Into @YourTable values 
(100,1306489), 
(125,898426), 
(150,907404) 

Select ID 
     ,Volume 
     ,RunningTotal = sum(Volume) over (Order by Volume Desc) 
From @YourTable 
Order By Volume Desc 

戻り

ID Volume RunningTotal 
100 1306489 1306489 
150 907404 2213893 
125 898426 3112319 

を覗いてください。実際のデータをテーブル変数にINSERTする必要はありません。

EDITは2008

Select ID 
     ,Volume 
     ,RowNr=Row_Number() over (Order by Volume Desc) 
    Into #Temp 
    From @YourTable 


Select A.ID 
     ,A.Volume 
     ,RunningTotal = sum(B.Volume) 
    From #Temp A 
    Join #Temp B on (B.RowNr<=A.RowNr) 
    Group By A.ID,A.Volume 
    Order By A.Volume Desc 
+0

これは私が探しているものかもしれませんが、私はエラーが表示され続けます:メッセージ11305、レベル15、状態10。私たちはSQL Server 2008 R2を使用しており、そのエラーコードを見てそれが言及パラレルデータウェアハウス機能は有効になっていない?? – Spartan46236

+0

@ Spartan46236申し訳ありませんが、2008年にはSum()はサポートされていません。代替品を提供するために数分を与えます –

+0

@ Spartan46236更新された回答のEDITをご覧ください –

1

GarethDが稼働して合計し、そのパフォーマンスを計算する複数の方法に決定的なリンクを提供する(グッドニュースは、ROW_NUMBER()2008でサポートされている)をサポートするために。正しいものは、最も簡単で速いものです。300倍速くて奇妙なアップデートです。これは、ソート列をカバーするインデックスを利用できるため、またはるかに簡単なためです。

私はSUM行は意味どのくらいのシンプルなデータベースが

SELECT 
    [Date], 
    TicketCount, 
    SUM(TicketCount) OVER (ORDER BY [Date] RANGE UNBOUNDED PRECEDING) 
FROM dbo.SpeedingTickets 
ORDER BY [Date]; 

適切なウィンドウ関数を提供する場合、これは明確にするために、ここでそれを繰り返す:すべてのチケットは、すべての上にカウント合計(無制限)の前に来たの行を日付で注文されたものを現在のものに変更(PRECEDING)します。

これは、奇妙なアップデートよりも300倍高速です。

VolumeTableのための同等のクエリは次のようになります。そこにソート列(ボリューム)上の指標であり、ABSが使用されていない場合、これははるかに高速になります

SELECT 
    ID, 
    Volume, 
    ABS(Volume) as SortValue, 
    SUM(Volume) OVER (ORDER BY ABS(Volume) DESC RANGE UNBOUNDED PRECEDING) 
FROM 
    VolumeTable 
ORDER BY ABS(Volume) DESC 

注こと。列に関数を適用すると、実際のソート値が索引に格納されている値と異なるため、オプティマイザは索引を使用できません。表が非常に大きく、パフォーマンスが低下した場合

、あなたは計算列を作成し、

関連する問題