2012-04-30 57 views
4

我的一位同事遇到了一個問題,我試圖幫助他。SQL Server查詢在列A中更改時重置,在列中運行總計

他有包含以下數據(樣本數據),在SQL視圖: -

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

他想將列添加到其保持的運行總計值列的視圖。

此列必須在類別更改時重置運行總計。

所以輸出數據必須是這樣的: -

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列,當類別改變時,我們將如何指示運行總數重置?

+1

哪個版本的合併?這對於SQL Server 2012來說非常簡單,因爲如果最終(完全)支持窗口函數。 –

+1

不幸的是SQL Server 2005。 –

+0

運行總量的順序如何計算?表中是否有日期字段? – Dibstar

回答

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 < = r1.row,可以確保第二個連接包含所有值< =當前行 - 即R1中的第3行將包含R2連接中的第1,2,3行。

+0

您能否請您向我解釋這是如何工作的,以及是否有指定類似於下面答案的命令的方式? – JsonStatham

+1

查看編輯 - 根據更改順序,您可以將ROW_NUMBER()子句的ORDER BY ...部分更改爲按照您認爲合適的順序進行訂購 – Dibstar

+0

我需要底部的訂單,以便我可以將其保存在查看 – JsonStatham

3

您可以使用ROW_NUMBER()功能與SQL Server的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 
+1

已經嘗試了兩個回答,並且運行時間超過6分鐘,下面的答案在3秒內運行。兩者都正常工作。 – JsonStatham