2011-10-26 96 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