我遇到了以下SQL UPDATE语句,该语句计算表中的运行总列数:
UPDATE N1 SET
RunningTotal = (SELECT SUM (SubTotal)
FROM #Sales X1
WHERE
N1.FiscalYear = X1.FiscalYear AND
X1.OrderNumber <= N1.OrderNumber)
FROM
#Sales N1
我之前没有见过这种类型的模式,由于搜索SQL语句有困难,我无法找到解释。具体来说,我想知道上述语句如何能够更新整个表;循环是如何发生的?
注意:声明工作正常; SSMS中的前后结果如下:
(我在Windows 10 x64上使用SQL Server 2017社区版。)
答案 0 :(得分:2)
这不是真正的循环,但我会解释:
UPDATE N1 SET
RunningTotal = ...
FROM #Sales N1
由于这个原因,它正在更新整个表格。更新中没有where子句,因此无论如何都会更新每一行。我个人更喜欢这种别名表格和对别名使用UPDATE,因为当你有复杂的更新时,它可以让你更容易查看更改。
内在部分:
SELECT SUM (SubTotal)
FROM #Sales X1
WHERE N1.FiscalYear = X1.FiscalYear AND
X1.OrderNumber <= N1.OrderNumber
获取每年之前且等于正在处理的订单的销售额总和。它不是在代码中循环;它确实每行运行一个子查询或返回数据。
答案 1 :(得分:1)
您的更新语句只是对当前OrderNumber之前的所有行进行求和。
让我告诉你另一种方法:
create table tbl (FiscalYear int, OrderDate date, OrderNumber int, SubTotal decimal(10,2), RunningTotal decimal(10,2)); insert into tbl values (2011, '20110531', 1, 5000.02, null), (2011, '20110531', 2, 1000.15, null), (2011, '20110531', 3, 700.25, null), (2011, '20110531', 4, 225.02, null), (2011, '20110531', 5, 1258.25, null), (2011, '20110531', 6, 1000.00, null), (2011, '20110531', 7, 695.20, null), (2011, '20110531', 8, 789.25, null), (2011, '20110531', 9, 2125.02, null); GO
CTE查询计算累积总数,第二个更新您的表格。
;with x as ( select FiscalYear, OrderDate, OrderNumber, SubTotal, sum(SubTotal) over (partition by FiscalYear order by FiscalYear, OrderDate, OrderNumber) as CumTotal from tbl ) update t set RunningTotal = CumTotal from tbl t join x on x.Fiscalyear = t.FiscalYear and x.OrderDate = t.OrderDate and x.OrderNumber = t.OrderNumber; GO
9 rows affected
select * from tbl; GO
FiscalYear | OrderDate | OrderNumber | SubTotal | RunningTotal ---------: | :------------------ | ----------: | :------- | :----------- 2011 | 31/05/2011 00:00:00 | 1 | 5000.02 | 5000.02 2011 | 31/05/2011 00:00:00 | 2 | 1000.15 | 6000.17 2011 | 31/05/2011 00:00:00 | 3 | 700.25 | 6700.42 2011 | 31/05/2011 00:00:00 | 4 | 225.02 | 6925.44 2011 | 31/05/2011 00:00:00 | 5 | 1258.25 | 8183.69 2011 | 31/05/2011 00:00:00 | 6 | 1000.00 | 9183.69 2011 | 31/05/2011 00:00:00 | 7 | 695.20 | 9878.89 2011 | 31/05/2011 00:00:00 | 8 | 789.25 | 10668.14 2011 | 31/05/2011 00:00:00 | 9 | 2125.02 | 12793.16
db&lt;&gt;小提琴here
答案 2 :(得分:1)
您问题的最佳解决方案是可更新的CTE:
WITH toupdate AS
(SELECT S.*,
SUM(SubTotal) OVER (PARTITION BY FiscalYear ORDER BY OrderNumber) AS new_RunningTotal
FROM #Sales S
)
UPDATE toupdate
SET RunningTotal = new_RunningTotal;
这没有连接或相关子查询。通常,窗口函数将比相关的子查询等价物快得多。可更新的CTE是SQL Server的一个非常好的功能,可以使您免于额外的JOIN
。