我的一位同事有一个问题我正试图帮助他。
他有一个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列,当类别发生变化时,我们如何指示运行总计重置?
答案 0 :(得分:4)
这对较大的表格表现不佳,但会完成工作!
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&lt; = r1.row,这可以确保第二个连接包含所有值&lt; =当前行 - 即R1中的第3行将包含R2连接中的第1,2,3行。
答案 1 :(得分:3)
您可以将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