【问题标题】:SQL Server Query, running total in view, reset when column A changesSQL Server 查询,在视图中运行总计,当 A 列更改时重置
【发布时间】:2012-05-09 23:29:47
【问题描述】:

我的一位同事有一个问题,我正试图帮助他解决。

他有一个 SQL 视图,其中包含以下数据(示例数据):-

Category          Value
Cat A             10
Cat A             20
Cat A             30
Cat B             15
Cat B             15
Cat C             10
Cat C             10

他想在视图中添加一列,以保持 Value 列的总和。

类别更改时,此列必须重置累计。

所以输出的数据一定是这样的:-

Category          Value       Running
Cat A             10          10
Cat A             20          30
Cat A             30          60
Cat B             15          15
Cat B             15          30
Cat C             10          10
Cat C             10          20

我们可以通过像这样将表格连接到自身来获得运行总数:-

select t1.id, t1.[count], SUM(t2.[count]) as sum
from TableA t1
inner join TableA t2 on t1.id >= t2.id
group by t1.id, t1.[count]
order by t1.id

问题是我们没有 ID 列,当类别更改时,我们如何指示累计重置??

【问题讨论】:

  • SQL Server 的哪个版本?这在 SQL Server 2012 中非常简单,因为 if finally(完全)支持窗口函数。
  • 不幸的是 SQL Server 2005。
  • 累计的顺序是如何计算的?表格中有日期字段吗?
  • 表格将按类别然后按值排序,因此应按照上面数据出现的顺序计算总数。请注意,order by 子句必须在执行运行总计的查询中,因为数据是从不允许 order by 子句的视图中提取的。

标签: tsql sql-server-2005 cumulative-sum


【解决方案1】:

这在较大的表上不会表现得特别好,但可以完成这项工作!

   select 'Cat A' as class,10 as value into #x
UNION ALL SELECT 'Cat A',20 
UNION ALL SELECT 'Cat A',30 
UNION ALL SELECT 'Cat B',15 
UNION ALL SELECT 'Cat B',15 
UNION ALL SELECT 'Cat C',10 
UNION ALL SELECT 'Cat C',10 

;WITH running_total AS
(
select *
,ROW_number() OVER (PARTITION BY class order by value ASC) as row 
from #x 
)
SELECT 
r1.class
,MAX(r1.value) as value
,SUM(r2.value) as running_total
FROM running_total r1
LEFT OUTER JOIN running_total r2 on r2.class = r1.class
                AND r2.row <= r1.row
GROUP BY 
r1.class
,r1.row

这通过使用公用表表达式 (CTE) 和窗口函数来工作。 CTE 的工作方式与子查询类似,其中第一部分(称为 running_total)根据值向每个类添加基于行的 ID。

Row_number() 按照文档中的 here 工作,但基本上它会根据您定义分区的方式自动递增(基本上与分组依据相同,但不必在主查询中分组)和按类的内置顺序.

在此示例中,按类划分确保每个新类别名称的最小值设置为 1 - 如果您想要一个不基于特定类别的总运行总数,您可以删除这部分子句。

CTE 的第二部分从 CTE 的第一部分中选择结果,并在类匹配的地方加入自身。通过加入 r2.row

【讨论】:

  • 您能否向我解释一下这是如何工作的,以及是否有一种方法可以像下面的答案一样指定订单?
  • 查看编辑 - 在更改顺序方面,您可以更改 ROW_NUMBER() 子句的 ORDER BY ... 部分以按您认为合适的方式进行排序
  • 我需要底部的 order by 以便将其保存在视图中
  • 只对视图外的结果进行排序。
【解决方案2】:

您可以将ROW_NUMBER() 函数与OUTER APPLY 结合使用

DECLARE @T TABLE (Category VARCHAR(5), Value INT)
INSERT INTO @T VALUES 
    ('Cat A', 10),
    ('Cat A', 20),
    ('Cat A', 30),
    ('Cat B', 15),
    ('Cat B', 15),
    ('Cat C', 10),
    ('Cat C', 10)

;WITH T AS
(   SELECT  Category, Value, ROW_NUMBER() OVER(PARTITION BY Category ORDER BY Value) [RowNumber]
    FROM    @T
)
SELECT  T1.Category,
        T1.Value,
        RunningTotal
FROM    T T1
        OUTER APPLY
        (   SELECT  SUM(Value) [RunningTotal]
            FROM    T T2
            WHERE   T2.Category = T1.Category
            AND     T2.RowNumber <= T1.RowNumber
        ) RunningTotal

【讨论】:

  • 已经尝试了两个答案,并且运行时间超过 6 分钟,而下面的答案运行时间为 3 秒。两者都可以正常工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
  • 2011-12-03
  • 2010-10-23
  • 2021-12-20
相关资源
最近更新 更多