SQL A查询,在视图中运行总计,在A列更改时重置

时间:2012-04-30 08:39:58

标签: tsql sql-server-2005 running-total

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

他有一个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列,当类别发生变化时,我们如何指示运行总计重置?

2 个答案:

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