2011-11-21 11 views
7

可能性の重複:
How do I calculate a running total in SQL without using a cursor?以前のすべての値の合計を取得しますか? - これまでの合計?

それは説明するのは少し難しいので、私は、私は例を挙げて欲しいもの紹介:

は、我々は次の表を考えてみましょうMonthProfit

[MonthId][Profit] 
1, 10 -- January 
2, 20 -- February 
3, 30 
4, 40 
5, 50 
6, 60 
7, 70 
8, 80 
9, 90 
10, 100 
11, 110 
12, 120 -- December 

profitはその月の利益を表します。

:私たちは月に10利益を持って、2月20、月に私たちは30

の総利益を持っている場合

しかし、私は次のように表示するビューを作成したいのですが私はそれを解決するために、今やった

[MonthId][Profit][ProfitTotal] 
1, 10, 10 -- January 
2, 20, 30 -- February 
3, 30, 60 
4, 40, 100 
5, 50, 150 
6, 60, 210 
7, 70, 280 
8, 80, 360 
9, 90, 450 
10, 100, 550 
11, 110, 660 
12, 120, 780 -- December 

は、このような図である。

SELECT [MonthId] 
     ,[Profit] 
     , (SELECT SUM([Profit]) 
     FROM MonthProfit 
     WHERE [MonthId] <= outer.[MonthId]) as ProfitTotal 
FROM MonthProfit as outer 

しかし、私はそれがすべてのすべての時間を詳述しているので、これはかなり遅いですと仮定し、それはVEのようではありません私にエレガントになりました。これを行う「良い」方法はありますか?

+2

http://stackoverflow.com/questions/814054/complicated-sql-query-for-a-running-total-column – JNK

+2

ただ、 "トータルSQLの実行" を検索しますこれに多くのヒットを得るでしょう。 – JNK

答えて

3

私はこれは

CREATE TABLE [dbo].[tbl_TotalPrevious](
[id] [int] IDENTITY(1,1) NOT NULL, 
[name] [varchar](50) NOT NULL, 
[values] [bigint] NOT NULL) 

INSERTデータTABLE

insert into tbl_TotalPrevious values ('A', 10) 
insert into tbl_TotalPrevious values ('B', 20) 
insert into tbl_TotalPrevious values ('C', 10) 
insert into tbl_TotalPrevious values ('D', 10) 
insert into tbl_TotalPrevious values ('E', 10) 
insert into tbl_TotalPrevious values ('F', 10) 
insert into tbl_TotalPrevious values ('G', 10) 
insert into tbl_TotalPrevious values ('H', 10) 
insert into tbl_TotalPrevious values ('I', 10) 
insert into tbl_TotalPrevious values ('J', 10) 
insert into tbl_TotalPrevious values ('K', 10) 
insert into tbl_TotalPrevious values ('L', 10) 
insert into tbl_TotalPrevious values ('M', 10) 
insert into tbl_TotalPrevious values ('N', 10) 
insert into tbl_TotalPrevious values ('O', 10) 
insert into tbl_TotalPrevious values ('P', 10) 
insert into tbl_TotalPrevious values ('Q', 10) 
insert into tbl_TotalPrevious values ('R', 10) 
insert into tbl_TotalPrevious values ('S', 10) 
insert into tbl_TotalPrevious values ('T', 10) 
insert into tbl_TotalPrevious values ('U', 10) 
insert into tbl_TotalPrevious values ('V', 10) 
insert into tbl_TotalPrevious values ('W', 10) 
insert into tbl_TotalPrevious values ('X', 10) 
insert into tbl_TotalPrevious values ('Y', 10) 

機能などを作成INTO要件ごとに結果を生成し、あなたの参考のためにここに小さな例を試してみました。単一のクエリから生成

ALTER FUNCTION testtotal 
(
    @id int 
) 
RETURNS int 
AS 
BEGIN 
    DECLARE @Result int 
    SELECT @Result = (SELECT SUM([values]) 
     FROM tbl_TotalPrevious 
     WHERE [id] <= @id) 

    RETURN @Result 

END 
GO 

結果

SELECT [id],[values], (dbo.testtotal(id)) as TotalVals FROM tbl_TotalPrevious 

はHOPE THE ABOVEはタイミングの問題であなたの目的を解決し、より速く必要に応じてデータを生成します。また

RESULTS IMAGE

+1

私のサブクエリとまったく同じことはしませんか?関数にのみカプセル化されていますか? –

+0

しかしこれを行うと、関数による時間とテーブルのスキャンが減少します。しかし、私はあなたが実装し、あなたが持っているライブデータの実行計画をテストする必要がありますと思います。 – Murtaza

-1

これは非常にエレガントではないようですが、正しく動作します。

あなたが改善したい場合、あなたはいくつかの選択肢があります。

  1. 挿入/更新値にまたはあなたがそれを作るしたい場合(トリガー)に更新されるテーブル内の3番目の列(ProfitTotal)を作ります選択時に;
  2. 索引を作成して高速化します。
  3. テーブルの統計情報を更新します。
0

このようなものを試してみると、一見一目瞭然です:-)。

create table #tab ([MonthId] int, [Profit] int) 

insert into #tab select 1, 10 -- January 
insert into #tab select 2, 20 -- February 
insert into #tab select 3, 30 
insert into #tab select 4, 40 
insert into #tab select 5, 50 
insert into #tab select 6, 60 
insert into #tab select 7, 70 
insert into #tab select 8, 80 
insert into #tab select 9, 90 
insert into #tab select 10, 100 
insert into #tab select 11, 110 
insert into #tab select 12, 120 -- December 

select t.*, t3.total 
from #tab t 
join (
    select t1.monthId, 
     sum(t2.profit) as total 
    from #tab t1 
    join #tab t2 on t1.monthId >= t2.monthId 
    group by t1.monthId 
) t3 on t.monthId = t3.monthId 
0
declare @MonthProfit table 
(
    [MonthId] int, 
    [Profit] int 
) 

insert into @MonthProfit values 
(1, 10),(2, 20),(3, 30),(4, 40), 
(5, 50),(6, 60),(7, 70),(8, 80), 
(9, 90),(10, 100),(11, 110),(12, 120) 

;with C as 
(
    select M.MonthId, 
     M.Profit 
    from @MonthProfit as M 
    where M.MonthId = 1 
    union all 
    select M.MonthId, 
     C.Profit + M.Profit 
    from @MonthProfit as M 
    inner join C 
     on M.MonthId = C.MonthId + 1 
) 
select C.MonthId, 
     C.Profit 
from C 
order by C.MonthId 
関連する問題