2011-10-26 64 views
0

可能重複:
Calculate a Running Total in SqlServer的最有效途徑計算運行值在SQL

考慮這個數據

 Day | OrderCount 
     1  3 
     2  2 
     3  11 
     4  3 
     5  6 

我怎樣才能得到這種積累定單計數的(運行值)結果集使用T-SQL查詢

 Day | OrderCount | OrderCountRunningValue 
     1  3   3 
     2  2   5 
     3  11   16 
     4  3   19 
     5  6   25 

我可以在實際查詢(使用#table)或在我的C#代碼隱藏中循環,但它很慢(考慮到我也獲得每天的訂單),當我處理數千條記錄時,尋找更好/更有效的方法希望沒有循環像遞歸CTE或其他東西。

任何想法將不勝感激。 TIA

+1

有很多答案在SO運行SQL總的問題。查看http://stackoverflow.com/questions/7357516/subquery-or-leftjoin-with-group-by-which-one-is-faster瞭解更多詳情。或者本文檔http://www.insidetsql.com/OVER_Clause_and_Ordered_Calculations.doc – MatBailie

+1

注意:上面引用的問題和文檔顯示,對於幾乎任何數據大小,遊標都快於半笛卡爾積。我強烈建議避免這種解決方案。 – MatBailie

回答

2

你似乎需要在客戶端,而不是另一個SQL查詢中使用這些結果,您可能最好不這樣做在SQL。

(在我的評論顯示了SQL中的「最佳」選項的鏈接的問題,如果這是逸岸必要的。)


可能會建議什麼是拉日和定單計數值作爲一個結果集(SELECT day, orderCount FROM yourTable ORDER BY day),然後計算C#中的運行總數。

您的C#代碼將能夠高效地遍歷數據集,並且幾乎可以肯定會勝過SQL方法。這樣做的作用是將一些負載從SQL Server轉移到Web服務器,但節省了整體(且顯着)的資源。

2
SELECT t.Day, 
     t.OrderCount, 
     (SELECT SUM(t1.OrderCount) FROM table t1 WHERE t1.Day <= t.Day) 
     AS OrderCountRunningValue 
FROM table t 
+1

請注意,這在較大的數據集上不能很好地縮放。第100條記錄將計算100行。 101st將重新計算所有這些行,還有一個。等等等等。它相當於半笛卡爾乘積。 – MatBailie

1
SELECT 
    t.day, 
    t.orderCount, 
    SUM(t1.orderCount) orderCountRunningValue 
FROM 
    table t INNER JOIN table t1 ON t1.day <= t.day 
group by t.day,t.orderCount 
+1

與KayKay的回答相同(雖然它使用了不同的表達式),但它遵循半笛卡爾乘積的相同邏輯。 – MatBailie

+0

啊我明白了,同一張表,但不同的別名 – dotnetlinc

0

CTE的救援(再次):

DROP TABLE tmp.sums; 
CREATE TABLE tmp.sums 
     (id INTEGER NOT NULL 
     , zdate timestamp not null 
     , amount integer NOT NULL 
     ); 

INSERT INTO tmp.sums (id,zdate,amount) VALUES 
(1, '2011-10-24', 1),(1, '2011-10-25', 2),(1, '2011-10-26', 3) 
,(2, '2011-10-24', 11),(2, '2011-10-25', 12),(2, '2011-10-26', 13) 
     ; 

WITH RECURSIVE list AS (
-- Terminal part 
    SELECT t0.id, t0.zdate 
    , t0.amount AS amount 
    , t0.amount AS runsum 
    FROM tmp.sums t0 
    WHERE NOT EXISTS (
     SELECT * FROM tmp.sums px 
     WHERE px.id = t0.id 
     AND px.zdate < t0.zdate 
     ) 
    UNION 
    -- Recursive part 
    SELECT p1.id AS id 
    , p1.zdate AS zdate 
    , p1.amount AS amount 
    , p0.runsum + p1.amount AS runsum 
    FROM tmp.sums AS p1 
    , list AS p0 
    WHERE p1.id = p0.id 
    AND p0.zdate < p1.zdate 
    AND NOT EXISTS (
     SELECT * FROM tmp.sums px 
     WHERE px.id = p1.id 
     AND px.zdate < p1.zdate 
     AND px.zdate > p0.zdate 
     ) 
    ) 
SELECT * FROM list 
ORDER BY id, zdate; 

輸出:

DROP TABLE 
CREATE TABLE 
INSERT 0 6 
id |  zdate  | amount | runsum 
----+---------------------+--------+-------- 
    1 | 2011-10-24 00:00:00 |  1 |  1 
    1 | 2011-10-25 00:00:00 |  2 |  3 
    1 | 2011-10-26 00:00:00 |  3 |  6 
    2 | 2011-10-24 00:00:00 |  11 |  11 
    2 | 2011-10-25 00:00:00 |  12 |  23 
    2 | 2011-10-26 00:00:00 |  13 |  36 
(6 rows) 
+0

你是指在問題的評論中提到的問題?哪裏有人建議這是一個重複的問題,看着這些問題將提供這樣的答案? – MatBailie

+0

不,我不看重複。這是一個100%原創的答案。我懷疑是否有人提出了遞歸解決方案。 – wildplasser

+0

現在我看到有一個。馬丁史密斯。對我來說沒有壞的公司。 – wildplasser