2016-11-04 82 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

採取偷看在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 

需要明確的是,該@YourTable僅用於示範的目的。應該不需要將實際數據插入到表變量中。

編輯以支持2008(好消息是ROW_NUMBER()在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並查看它提到的錯誤代碼並行datawarehouse功能未啓用? – Spartan46236

+0

@ Spartan46236對不起,Sum()Over在2008年不支持。給我幾分鐘給你一個替代方案 –

+0

@ Spartan46236參見編輯更新回答 –

1

GarethD提供明確的鏈接,計算運行總和,其性能的多種方式。正確的一個是最簡單和最快,300倍更快,然後古怪的更新。這是因爲它可以利用覆蓋排序列的任何索引,並且因爲它更簡單。

我重複了在這裏當數據庫提供適當的窗口函數

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

SUM行表示明確如何更簡單的是這樣的:在它以前所有的(無界)的行總和所有票數(PRECEDING)當前版本

結果比奇怪的更新快300倍。

VolumeTable等效查詢是:

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 

注意,這將是快了不少,如果有對排序列(卷)的索引,並且不使用ABS。在列上應用任何函數意味着優化器不能使用覆蓋它的任何索引,因爲實際的排序值與存儲在索引中的值不同。

如果表格非常大並且性能受損,則可以創建計算列並在其上創建索引