用于运行整体解决方案的不熟悉的SQL UPDATE语句

时间:2018-06-08 17:26:49

标签: sql sql-server running-total

我遇到了以下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中的前后结果如下:

enter image description here

(我在Windows 10 x64上使用SQL Server 2017社区版。)

3 个答案:

答案 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