更新查询 - 前行 x 和当前行 y 的总和

Posted

技术标签:

【中文标题】更新查询 - 前行 x 和当前行 y 的总和【英文标题】:Update Query - Sum of previous row x and current row y 【发布时间】:2021-10-16 13:14:27 【问题描述】:

我有一个 LedgerData 表,需要更新余额。

表结构

CREATE TABLE [dbo].[LedgerData]
(
    [Id] INT NOT NULL,
    [CustomerId] INT NOT NULL,
    [Credit] INT,
    [Debit] INT,
    [Balance] INT
    CONSTRAINT [PK_dbo_LedgerData] 
        PRIMARY KEY CLUSTERED ([Id] ASC)
                    WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                          IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                          ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];

样本数据

INSERT INTO [dbo].[LedgerData] VALUES (1, 1, 50, 0, 0);
INSERT INTO [dbo].[LedgerData] VALUES (2, 1, 0, 25, 0);
INSERT INTO [dbo].[LedgerData] VALUES (3, 2, 0, 75, 0);
INSERT INTO [dbo].[LedgerData] VALUES (4, 1, 0, 10, 0);
INSERT INTO [dbo].[LedgerData] VALUES (5, 2, 5, 0, 0);
INSERT INTO [dbo].[LedgerData] VALUES (6, 1, 10, 25, 0);

我尝试更新客户明智的余额列ORDER BY [Id] ASC,但它没有按预期更新。我也探索了sql query to calculate sum and add sum from previous rows

请帮我计算余额栏Balance = (Previous Row Balance + Credit - Debit)

【问题讨论】:

请将您的预期结果添加到您的问题中。 明确一点:id 是定义顺序的列,对吧? 停下来,只是不要。数据应保持无冗余以避免出现不一致的可能性。因此,将表格的部分集合上的总和写入其中并不是一件好事。删除列balance。如果需要余额,可以随时查询得到正确的结果。为方便起见,您可以创建一个视图来存储此类查询,这样您就不必每次都重复它。 【参考方案1】:

理想情况下,这是你应该做的事情作为INSERT数据,通过获取以前的值(并锁定表,以便其他INSERT语句不会发生以避免竞争) 然后为Balance 提供一个值。但是,您可以 UPDATE 具有累积 SUM 和可更新 CTE 的所有行:

WITH CTE AS(
    SELECT ID,
           CustomerID,
           Balance,
           0 + SUM(Credit) OVER (PARTITION BY CustomerID ORDER BY ID) - SUM(Debit) OVER (PARTITION BY CustomerID ORDER BY ID) AS NewBalance
    FROM dbo.LedgerData)
UPDATE CTE
SET Balance = NewBalance;
GO

SELECT *
FROM dbo.LedgerData;

或者,根本不存储聚合值,并使用VIEW,以便始终可以使用我在 CTE 中使用的相同表达式(准确地)计算该值。例如:

CREATE VIEW dbo.LedgerDataCumulative
AS
    SELECT Id,
           CustomerId,
           Credit,
           Debit,
           SUM(Credit) OVER (PARTITION BY CustomerID ORDER BY ID) - SUM(Debit) OVER (PARTITION BY CustomerID ORDER BY ID) AS Balance
    FROM dbo.LedgerData;
GO

【讨论】:

【参考方案2】:

可以使用单个窗口函数执行更新。

with upd_cte as (
    select *, sum([Credit]-[Debit]) over (partition by customerId order by id) sum_over
    from #LedgerData)
update upd_cte
set Balance=sum_over;

【讨论】:

以上是关于更新查询 - 前行 x 和当前行 y 的总和的主要内容,如果未能解决你的问题,请参考以下文章

BIEE时间序列函数

树状数组基本模版(区间更新,单点查询)

使用 T-SQL 根据先前行的值逐行更新表

[模板]二维树状树组 单点修改 区间查询

在工作表中组合行和总和值

使用子查询更新语句