【问题标题】:Running Total Minus运行总减
【发布时间】:2022-01-10 02:40:45
【问题描述】:

我正在尝试使用此代码计算 SQL 中的负运行总计,但它没有给我预期的结果。在 01/2021 日期之后,我想减去每个月的销售额。

select Name, Date, Sales, MinusRunningTotal = B.Sales - SUM(A.sales) 
              OVER (PARTITION BY Name ORDER BY Date)
From TableA A 
Join TableB B on A.ID = B.ID
Where Date > '01/2021'

这就是数据的显示方式

Name Date      Sales    
A    01/2021    10         
A    02/2021    1           
A    03/2021    2           
A    04/2021    3  

这就是我想要实现的目标

Name Date      Sales    MinusRunningTotal
A    01/2021    10         10
A    02/2021    1           9
A    03/2021    2           7
A    04/2021    3           4

【问题讨论】:

    标签: sql sql-server tsql


    【解决方案1】:

    如果该数据已存在于包含namedatesales 列的表中,请尝试:

    SELECT [name],
           [date],
           [sales],
           FIRST_VALUE([sales]) OVER (PARTITION BY [name]
                                          ORDER BY [date]) * 2 
               -   SUM([sales]) OVER (PARTITION BY [name]
                                          ORDER BY [date]
                          ROWS UNBOUNDED PRECEDING) AS minus_running_total                                      
     FROM my_table
    

    sql fiddle

    这会计算当前名称的所有先前销售额(包括当前值)

    `SUM([sales]) OVER (PARTITION BY [name] 
                            ORDER BY [date]`)
    

    这会计算当前名称的第一个时间值 X 2:

    `FIRST_VALUE([sales]) OVER (PARTITION BY [name]
                                    ORDER BY [date]) * 2`
    

    所以第一行计算为 (10 x 2) - 10 = 10

    第二行是 (10 x 2) - (10 + 1) = 9

    第三行是 (10 x 2) - (10 + 1 + 2) = 7

    【讨论】:

    • 一个好的答案包括解释它是如何工作的——除了工作代码。
    【解决方案2】:
    select Name, Date, Sales, 
    ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Date) as RN into 
    #temp2 From table 
    
    select Name, Date, Sales, 
    case when rn != 1 
    then (select sale from #temp2 where RN = 1) - sum(sales) 
                  OVER (PARTITION BY Name ORDER BY Date
                  rows between UNBOUNDED PRECEDING and current row) 
              else sales end
    From #temp2
    

    【讨论】:

    • 一个好的答案包括解释它是如何工作的——除了工作代码。
    【解决方案3】:

    我制作了一个表格 sss,其中包含您在第二个代码部分中显示的数据。此查询将给出您想要的结果。如果需要加入其他数据,请在下面称为 xs 的 CTE 中进行。

    with
    xs as (
        select name, dt, sales, sales tot,
            ROW_NUMBER() over (partition by name order by dt) n
        from sss
        ),
    rec as (
        select * from xs where n = 1
        
        union all
        
        select xs.name, xs.dt, xs.sales, rec.tot - xs.sales, xs.n
        from rec
        join xs on rec.name = xs.name
            and xs.n = rec.n + 1
        )
    select *
    from rec
    

    它是如何工作的:

    在 CTE(公用表表达式)xs 中,我们按 dt 升序对与给定名称关联的行编号。

    CTE rec 是一个递归查询,首先通过“n = 1”过滤获取与名称关联的组的第一行。这成为输出的第一行。 rec 的第二部分获取后续行,其中新行的 n 等于前一行的 n + 1。通过从前一行 tot 中减去新行的销售额得到所需的运行总计,保留在列 tot 中。

    【讨论】:

    • 一个好的答案包括解释它是如何工作的——除了工作代码。
    猜你喜欢
    • 1970-01-01
    • 2019-05-20
    • 2018-04-01
    • 2018-05-12
    • 1970-01-01
    • 2018-04-01
    • 2020-10-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多