Totale parziale per record raggruppati nella tabella
-
22-07-2019 - |
Domanda
Ho una tabella come questa (Oracle, 10)
Account Bookdate Amount
1 20080101 100
1 20080102 101
2 20080102 200
1 20080103 -200
...
Ciò di cui ho bisogno è una nuova tabella raggruppata per Ordine account in base all'account asc e Bookdate asc con un campo totale parziale, come questo:
Account Bookdate Amount Running_total
1 20080101 100 100
1 20080102 101 201
1 20080103 -200 1
2 20080102 200 200
...
C'è un modo semplice per farlo?
Grazie in anticipo.
Soluzione
Hai davvero bisogno del tavolo extra?
Puoi ottenere quei dati di cui hai bisogno con una semplice query, che puoi ovviamente creare come vista se vuoi che appaia come una tabella.
Questo ti darà i dati che stai cercando:
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Questo creerà una vista per mostrarti i dati come se fosse una tabella:
create or replace view t2
as
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Se hai davvero bisogno della tabella, vuoi dire che ti serve costantemente aggiornata? o solo uno uno? Ovviamente se è una tantum puoi semplicemente " creare una tabella come selezionare " utilizzando la query sopra.
I dati di test che ho usato sono:
create table t(account number, bookdate date, amount number);
insert into t(account, bookdate, amount) values (1, to_date('20080101', 'yyyymmdd'), 100);
insert into t(account, bookdate, amount) values (1, to_date('20080102', 'yyyymmdd'), 101);
insert into t(account, bookdate, amount) values (1, to_date('20080103', 'yyyymmdd'), -200);
insert into t(account, bookdate, amount) values (2, to_date('20080102', 'yyyymmdd'), 200);
commit;
modifica:
dimenticato di aggiungere; hai specificato che volevi ordinare la tabella - questo non ha davvero senso, e mi fa pensare che intendi davvero che volevi la query / vista - l'ordinamento è il risultato della query che esegui, non qualcosa che è inerente a la tabella (ignorando le tabelle organizzate dall'indice e simili).
Altri suggerimenti
Inizierò con questo caveato molto importante: NON creare una tabella per contenere questi dati. Quando lo fai scoprirai che è necessario mantenerlo che diventerà un mal di testa senza fine. Scrivi una vista per restituire la colonna aggiuntiva se vuoi farlo. Se stai lavorando con un data warehouse allora forse faresti qualcosa del genere, ma anche in questo caso sbaglierai sul lato di una vista a meno che tu non riesca semplicemente a ottenere il rendimento di cui hai bisogno con gli indici, hardware decente, ecc.
Ecco una query che restituirà le righe nel modo in cui ne hai bisogno.
SELECT
Account,
Bookdate,
Amount,
(
SELECT SUM(Amount)
FROM My_Table T2
WHERE T2.Account = T1.Account
AND T2.Bookdate <= T1.Bookdate
) AS Running_Total
FROM
My_Table T1
Un'altra possibile soluzione è:
SELECT
T1.Account,
T1.Bookdate,
T1.Amount,
SUM(T2.Amount)
FROM
My_Table T1
LEFT OUTER JOIN My_Table T2 ON
T2.Account = T1.Account AND
T2.Bookdate <= T1.Bookdate
GROUP BY
T1.Account,
T1.Bookdate,
T1.Amount
Provali entrambi per le prestazioni e vedi quale funziona meglio per te. Inoltre, non li ho testati accuratamente oltre l'esempio che hai fornito, quindi assicurati di testare alcuni casi limite.
Usa le analisi, proprio come nella tua ultima domanda:
create table accounts
( account number(10)
, bookdate date
, amount number(10)
);
delete accounts;
insert into accounts values (1,to_date('20080101','yyyymmdd'),100);
insert into accounts values (1,to_date('20080102','yyyymmdd'),101);
insert into accounts values (2,to_date('20080102','yyyymmdd'),200);
insert into accounts values (1,to_date('20080103','yyyymmdd'),-200);
commit;
select account
, bookdate
, amount
, sum(amount) over (partition by account order by bookdate asc) running_total
from accounts
order by account,bookdate asc
/
uscita:
ACCOUNT BOOKDATE AMOUNT RUNNING_TOTAL
---------- -------- ---------- -------------
1 01-01-08 100 100
1 02-01-08 101 201
1 03-01-08 -200 1
2 02-01-08 200 200