2011-11-21 18 views
7

Eventuali duplicati:
How do I calculate a running total in SQL without using a cursor?Ottieni la somma di tutti i valori precedenti? - Totale finora?

E 'un po' difficile da spiegare, così ti faccio vedere quello che voglio con un esempio:

Consente di dire che abbiamo la seguente tabella 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 

La colonna profit rappresenta l'utile per quel mese.

Tuttavia, se abbiamo 10 di profitto nel mese di gennaio, e il 20 Febbraio, nel mese di febbraio abbiamo un profitto totale di 30.

quindi mi piacerebbe creare una vista che mostra la seguente:

[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 

Quello che ho fatto oggi per risolverlo, è una vista simile a questo:

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

Tuttavia, presumo che ciò è piuttosto lento perché deve raccontare tutto ogni volta, e non sembra ve ry elegante per me. C'è un "buon" modo per farlo?

+2

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

+2

Basta cercare "Running SQL totale" e si otterrà molti successi su questo. – JNK

risposta

3

ho cercato un piccolo esempio qui per il vostro riferimento questo genera i risultati secondo le esigenze

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

inserire i dati nella tabella

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) 

Creare una funzione ad es.

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 

risultati generati da una query UNICO

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

Spero che quanto sopra risolve il fine con il problema di temporizzazione e genera il più rapido dei dati come richiesto.

RESULTS IMAGE

+1

Non fa esattamente la stessa cosa della mia subquery? Solo incapsulato in una funzione? –

+0

Ma facendo ciò diminuirà comunque la scansione del tempo e della tabella a causa di una funzione. ma penso che dovresti implementare e testare il tuo piano di esecuzione per i dati live che hai. – Murtaza

-1

Questa sembra un'opzione non molto elegante ma funziona correttamente.

Se si vuole migliorare, si hanno diverse scelte:

  1. fare una terza colonna della tabella (la ProfitTotal) che verrà aggiornato (trigger) sui valori di inserimento/aggiornamento o se si desidera renderlo su selezionare;
  2. Creare un indice per renderlo più veloce;
  3. Aggiorna le statistiche della tabella.
0

Provare qualcosa di simile qui sotto, a prima vista sembra buono :-).

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 
Problemi correlati