为了简洁,我省略了所有光标设置和临时表中的SELECT。基本上,此代码计算每个事务的所有事务的运行余额。
WHILE @@fetch_status = 0
BEGIN
set @balance = @balance+@amount
insert into @tblArTran values ( --from artran table
@artranid, @trandate, @type,
@checkNumber, @refNumber,@custid,
@amount, @taxAmount, @balance, @postedflag, @modifieddate )
FETCH NEXT FROM artranCursor into
@artranid, @trandate, @type, @checkNumber, @refNumber,
@amount, @taxAmount,@postedFlag,@custid, @modifieddate
END
受到另一个问题答案的代码的启发,
SELECT @nvcConcatenated = @nvcConcatenated + C.CompanyName + ', '
FROM tblCompany C
WHERE C.CompanyID IN (1,2,3)
我想知道如果得到我的意思,SQL是否能够以与连接字符串相同的方式对数字求和。也就是说,每行创建一个“运行平衡”,而不使用游标。
有可能吗?
答案 0 :(得分:20)
您可能需要在此处查看对局部变量解决方案的更新:http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal.aspx
DECLARE @SalesTbl TABLE (DayCount smallint, Sales money, RunningTotal money)
DECLARE @RunningTotal money
SET @RunningTotal = 0
INSERT INTO @SalesTbl
SELECT DayCount, Sales, null
FROM Sales
ORDER BY DayCount
UPDATE @SalesTbl
SET @RunningTotal = RunningTotal = @RunningTotal + Sales
FROM @SalesTbl
SELECT * FROM @SalesTbl
优于所有其他方法,但对保证行顺序有一些疑问。当临时表被索引时似乎工作正常..
答案 1 :(得分:10)
SQL 可以创建运行总计而不使用游标,但它是少数几种情况之一,其中游标实际上比基于集合的解决方案更高效(给定SQL Server中当前可用的运算符)。或者,CLR功能有时可以很好地发挥作用。 Itzik Ben-Gan在SQL Server Magazine上发表了关于运行聚合的优秀系列。该系列节目于上个月结束,但如果您有在线订阅,则可以访问所有文章。
编辑:这是his latest article in the series(SQL CLR)。 鉴于您可以通过购买一个月的在线月票 - 少于6美元来访问整个系列 - 如果您有兴趣从各个角度查看问题,那么值得您花些时间。 Itzik是Microsoft MVP和非常明亮的TSQL编码器。
答案 2 :(得分:8)
在Oracle
和PostgreSQL 8.4
中,您可以使用窗口函数:
SELECT SUM(value) OVER (ORDER BY id)
FROM mytable
在MySQL
中,您可以将会话变量用于相同目的:
SELECT @sum := @sum + value
FROM (
SELECT @sum := 0
) vars, mytable
ORDER BY
id
在SQL Server
中,这是一个罕见的光标是首选解决方案的任务示例。
答案 3 :(得分:4)
计算每条记录的运行总计的示例,但前提是记录的OrderDate位于同一日期。一旦OrderDate用于不同的一天,那么新的运行总计将在新的一天开始并累积:(假设表格结构和数据)
select O.OrderId,
convert(char(10),O.OrderDate,101) as 'Order Date',
O.OrderAmt,
(select sum(OrderAmt) from Orders
where OrderID <= O.OrderID and
convert(char(10),OrderDate,101)
= convert(char(10),O.OrderDate,101))
'Running Total'
from Orders O
order by OrderID
以下是使用示例订单表从查询返回的结果:
OrderId Order Date OrderAmt Running Total
----------- ---------- ---------- ---------------
1 10/11/2003 10.50 10.50
2 10/11/2003 11.50 22.00
3 10/11/2003 1.25 23.25
4 10/12/2003 100.57 100.57
5 10/12/2003 19.99 120.56
6 10/13/2003 47.14 47.14
7 10/13/2003 10.08 57.22
8 10/13/2003 7.50 64.72
9 10/13/2003 9.50 74.22
请注意,“Running Total”的值从10.50开始,然后变为22.00,最后为OrderID 3的23.25,因为所有这些记录都具有相同的OrderDate(10/11/2003)。但是当显示OrderID 4时,重置运行总计,并且运行总计重新开始。这是因为OrderID 4的OrderDate具有不同的日期,然后OrderID为1,2和3.通过使用相关的子查询再次计算每个唯一日期的此运行总计,尽管需要额外的WHERE条件,确定不同记录的OrderDate需要在同一天。通过使用CONVERT函数将OrderDate截断为MM / DD / YYYY格式来完成此WHERE条件。
答案 4 :(得分:4)
在SQL Server 2012及更高版本中,您可以直接对原始表使用Sum
窗口函数:
SELECT
artranid,
trandate,
type,
checkNumber,
refNumber,
custid,
amount,
taxAmount,
Balance = Sum(amount) OVER (ORDER BY trandate ROWS UNBOUNDED PRECEDING),
postedflag,
modifieddate
FROM
dbo.Sales
;
与所有解决方案相比,这将表现得非常好,并且不会出现“古怪更新”中发现的错误。
请注意,您应尽可能使用ROWS
版本; RANGE
版本可能表现不佳。
答案 5 :(得分:2)
您可以在select子句中包含相关子查询。 (对于非常大的结果集,这将表现不佳)但
Select <other stuff>,
(Select Sum(ColumnVal) From Table
Where OrderColumn <= T.OrderColumn) As RunningTotal
From Table T
Order By OrderColumn
答案 6 :(得分:1)
您可以执行运行计数,这是一个示例,请记住,这实际上并不是那么快,因为它必须扫描每一行的表,如果您的表很大,这可以非常耗时且昂贵
create table #Test (id int, Value decimal(16,4))
insert #Test values(1,100)
insert #Test values(2,100)
insert #Test values(3,100)
insert #Test values(4,200)
insert #Test values(5,200)
insert #Test values(6,200)
insert #Test values(7,200)
select *,(select sum(Value) from #Test t2 where t2.id <=t1.id) as SumValues
from #test t1
id Value SumValues
1 100.0000 100.0000
2 100.0000 200.0000
3 100.0000 300.0000
4 200.0000 500.0000
5 200.0000 700.0000
6 200.0000 900.0000
7 200.0000 1100.0000
答案 7 :(得分:1)
在SQLTeam上,还有一个关于计算运行总计的article。比较了3种方法,以及一些性能测量:
游标远远超过其他解决方案,但如果你不能使用游标,至少还有另一种选择。
答案 8 :(得分:0)
SELECT @nvcConcatonated
位仅返回单个连接值。 (虽然它是按行计算中间值,但您只能检索最终值。)
所以,我认为答案是否定的。如果您想要一个单一的最终总和值,您当然只需使用SUM
。
我不是说你不能这样做,我只是说你不能用这个'技巧'做到这一点。
答案 9 :(得分:0)
请注意,使用变量来完成此操作(如下所示)可能会在多处理器系统中失败,因为可以在不同的处理器上计算单独的行,并且可能最终使用相同的起始值。我的理解是可以使用查询提示强制它使用单个线程,但我没有那些方便的信息。
更新@SalesTbl SET @RunningTotal = RunningTotal = @RunningTotal + Sales 来自@SalesTbl
使用其他选项之一(光标,窗口函数或嵌套查询)通常是获得可靠结果的最安全的选择。
答案 10 :(得分:0)
选择TransactionDate,金额,金额+(来自交易x的x.amount,其中x.TransactionDate&lt; Transactions)来自交易的运行总计
,其中 x.TransactionDate&lt;交易 可以是代表除当前记录之外的所有先前记录的任何条件