Data, Quantita
01/10/2009 5
02/10/2009 4
03/10/2009 2
04/10/2009 8
05/10/2009 9
vorrei fare una query che, per ogni data, mi visualizzi la quantit� totale,
cio�:
Data, Totale
01/10/2009 5
02/10/2009 9 (cio� 5 + 4)
03/10/2009 11 (cio� 5 + 4 + 2)
04/10/2009 19 ....
05/10/2009 28
Come posso fare?
Grazie 1000
Dino
> vorrei fare una query che, per ogni data, mi visualizzi la quantit�
> totale, cio�:
>
> Data, Totale
> 01/10/2009 5
> 02/10/2009 9 (cio� 5 + 4)
> 03/10/2009 11 (cio� 5 + 4 + 2)
> 04/10/2009 19 ....
> 05/10/2009 28
>
> Come posso fare?
SELECT Data, SUM(Quantita) AS QtaTotale
FROM tabella
GROUP BY Data
--
David Martin
Ciao Dino,
qui un paio di soluzioni
----
USE Tempdb
GO
CREATE TABLE dbo.Evento(Data Datetime, Quantita int)
INSERT INTO dbo.Evento
SELECT '20091001', 5 UNION ALL
SELECT '20091002', 4 UNION ALL
SELECT '20091003', 2 UNION ALL
SELECT '20091004', 8 UNION ALL
SELECT '20091005', 9
--Soluzione1
SELECT E.Data,SUM(E1.Quantita) AS Progressivo
FROM dbo.Evento E
INNER JOIN
dbo.Evento E1 ON E.Data>=E1.Data
GROUP BY E.Data
ORDER BY E.Data
--Soluzione2
SELECT E.Data,
(SELECT SUM(E1.Quantita)
FROM dbo.Evento AS E1
WHERE E.Data>=E1.Data) AS Progressivo
FROM dbo.Evento E
ORDER BY E.Data
DROP TABLE dbo.Evento
----
Ciao
--
Giorgio Rancati
[Office Access MVP]
"David Martin" <david....@libero.it> ha scritto nel messaggio
news:7n6qg9F...@mid.individual.net...
"David Martin" <david....@libero.it> ha scritto nel messaggio
news:7n6qg9F...@mid.individual.net...
Scusa Dino,
semplicemente ho letto il tuo post troppo velocemente e non ho capito
cosa chiedevi.
Ti devo una birra ;-)
--
David Martin
> Grazie 1000 Giorgio, la tua soluzione � perfetta.
> Metto 2 tabelle identiche e faccio la join su >= anzich� il solo =...
>
Integro con una soluzione in pi�, adatta se usi almeno SQL 2005, in presenza
di molte righe nella tabella dove devi calcolare i progressivi si dimostra
molto pi� performante. Lo scotto � che devi avere una funzione di appoggio.
Ovviamente posto solo per completezza, visto che dici di avere una tabella
dove la data � PK, di conseguenza � ben difficile che tu abbia moltissime
righe (20 anni fanno solo 7000 righe, ma anche con questi numeri puoi vedere
una netta differenza tra le 3 soluzioni), quella che si basa sulle cte gira
da me in modo istantaneo mentre la soluzione con il self join impiega 3
secondi. Per carit� pu� essere nulla di problematico per il tuo caso
specifico, ma magari in futuro potrebbe tornarti utile.
------- ------- -------
set nocount on
use tempdb
go
create table dbo.Evento(Data Datetime not null primary key clustered,
Quantita int not null)
go
create function dbo.ufnNext (@dtm datetime, @int int)
returns table as
return (
select top 1 Data, @int + Quantita as Quantita
from dbo.Evento
where Data > ISNULL(@dtm,'19000101')
order by Data
)
go
declare @int int
set @int= 1
while @int < 7000 -- Un 20 anni di righe
begin
insert into dbo.Evento
select dateadd (dd, @int, '20000101'), RAND() * 100
set @int= @int + 1
end
go
print 'Con CTE, inizio:' + convert (varchar, getdate(), 108)
-- (C) Idea by Marc :-)
;with cteNext as (
select Data, Quantita
from dbo.ufnNext(null,0)
union all
select n.Data, n.Quantita
from cteNext c cross apply dbo.ufnNext(c.Data, c.Quantita) n
)
select Data, Quantita
from cteNext
order by Data
option (maxrecursion 0)
print 'Con CTE, fine:' + convert (varchar, getdate(), 108)
print 'Con self join, inizio:' + convert (varchar, getdate(), 108)
SELECT E.Data,SUM(E1.Quantita) AS Progressivo
FROM dbo.Evento E
INNER JOIN
dbo.Evento E1 ON E.Data>=E1.Data
GROUP BY E.Data
ORDER BY E.Data
print 'Con self join, fine:' + convert (varchar, getdate(), 108)
go
drop function dbo.ufnNext
drop table dbo.Evento
...mmm... il copyright sulle query, interessante.... :-)
marc.
Molto bella, marc � sempre forte!
In attesa che ms completi le window functions introdotte con la versione
2005, questa soluzione � l'ideale quando ci sono molte righe.
:-)
Ciao Giorgio,
Grazie mille anzitutto.
Quel tipo di soluzione, nella mia testa, non sostituisce tanto [o solo]
le carenze di sintassi di sql 2005/2008 in fatto di window functions.
Piᅵ che altro permette un calcolo progressivo generalizzato e andrebbe
rimpiazzata dalla mia amata [platonicamente visto che ms non ci sente da
quell'orecchio] Previous function.
Usando l'inline function Next ᅵ possibile calcolare lifo e fifo,
riordini e code in tempi quasi decenti, cosa che non ᅵ possibile con le
window functions, anche complete.
Lo standard ANSI rifiuta categoricamente di approcciare l'estrazione dei
dati in modo progressivo tagliando fuori, a mio modesto avviso, una
fetta consistente di necessitᅵ molto reali e concrete, che vengono
quindi risolte con cursori e altre sintassi brutte, sporche e cattive.
E, per concludere, escludendo che ANSI cambi apporoccio e escludendo che
Microsoft faccia qualcosa di innovativo, resta da sperare che Oracle o
DB2 lo facciano in modo autonomo e che Microsoft proceda di conseguenza,
come da tradizione, con un bel cut e paste.
> Giorgio Rancati
> [Office Access MVP]
marc.
Oracle lo fa, vedi ad esempio
http://www.oracle.com/technology/oramag/code/tips2005/062005.html
Ho letto che anche Db2 lo fa alla stessa maniera ma non ritrovo il link,
quidi rimaniamo nella speranza di un "cut e paste"
:-)
--
> Lo standard ANSI rifiuta categoricamente di approcciare l'estrazione dei
> dati in modo progressivo tagliando fuori, a mio modesto avviso, una fetta
> consistente di necessitᅵ molto reali e concrete, che vengono quindi
> risolte con cursori e altre sintassi brutte, sporche e cattive.
>
Forse quelli che lavorano dietro l'ANSI si sono assuefatti con gli approcci
tradizionali e preferiscono:
- Chi ha hw con i strcontricacchi (ma fino ad un certo punto perchᅵ
esisteranno sempre casi reali in cui i dati sono tali da richiedere dell'hw
cosᅵ potente che ancora non esiste) usa gli approcci classici a colpi di
join per il calcolo al volo dei running totals, tanto tutto l'inutile e
grosso overhead di ricalcolare continuamente gli stessi subtotali viene
nascosto dalla grossa disponibilitᅵ di hw;
- Gli altri precalcolano quello che serve e lo tengono in tabella, mantendo
aggiornati i running totals calcolati e storati in modo periodico e/o
realtime (ma su fette piccole) a colpi di trigger o simili lato applicativo.
Forse c'ᅵ il timore che l'introduzione di nuove istruzioni per
l'elaborazione riga per riga, possa facilmente creare dei casi reali dove
fino ad un certo giorno tutto fila liscio, e poi in breve tempo i tempi di
elaborazione dei dati al volo diventano eccessivi, determinando quindi una
manutenzione pesante sul DB per riportare questi casi in uno dei due
descritti sopra. Nel senso, che, immaginando uno sviluppo futuro
potenzialmente dannoso per i calcoli al volo, forse in ANSI pensano che sia
meglio partire subito gestendo i dati in modo meno a real-time.
In questo caso si parla si running totals e per quelli il completamento
delle windows function basterebbe e immagino, pur non avendo piᅵ
informazioni da tempo, che anche Sql sia in arrivo su questo fronte.
I problemi nascono quando il calcolo progressivo non ᅵ una semplice
somma ma, per esempio, una somma tagliata, del tipo:
Val. Running.
1 1
2 3
-2 1
-2 0 !!
3 3
Le windows functions, bellissime, utilissime e indispensabili in
moltissimi casi, continuano a basarsi sugli operatori preconfezionati
sum, count, ecc e non permettono un vero calcolo progressivo "libero".
A questo mi riferivo. Il completamento della sintassi di Over risolverᅵ
completamente il caso postato da Dino M., l'utilizzo della Next ᅵ nato
per il calcolo del lifo e di quelle robe lᅵ.
> Giorgio Rancati
> [Office Access MVP]
marc.
s�, mi riferivo al caso postato da Dino.
>l'utilizzo della Next � nato per il calcolo del lifo e di quelle robe l�.
ok.
--
Ciao,
anche se capisco che sarebbe ingenuo ignorare che dietro il comitato
ansi si muovano interessi enormi, spero proprio che non sia cosᅵ.
ansi dovrebbe ignorare tutte queste questioni e occuparsi della teoria
dell'estrazione dei dati ed elaborare una sintassi coerente, sensata e
solida che permetta di risolvere le problematiche relative ai db.
Che poi questa sintassi vega usata per il calcolo al volo, per lo
storage ridondante via trigger o altro non dovrebbe contare nulla.
marc.