2016-11-04 83 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。在列上应用任何函数意味着优化器不能使用覆盖它的任何索引,因为实际的排序值与存储在索引中的值不同。

如果表格非常大并且性能受损,则可以创建计算列并在其上创建索引