Correndo total em registros agrupados na tabela
-
22-07-2019 - |
Pergunta
Eu tenho uma tabela como esta (Oracle, 10)
Account Bookdate Amount
1 20080101 100
1 20080102 101
2 20080102 200
1 20080103 -200
...
O que eu preciso é nova tabela agrupados por ordem Conta por asc Conta e Bookdate asc com um campo de execução total, como este:
Account Bookdate Amount Running_total
1 20080101 100 100
1 20080102 101 201
1 20080103 -200 1
2 20080102 200 200
...
Existe uma maneira simples de fazê-lo?
Agradecemos antecipadamente.
Solução
Você realmente precisa da tabela extra?
Você pode obter os dados que você precisa com uma consulta simples, que você pode obviamente criar como uma visão, se você quer que ele apareça como uma tabela.
Isto fará você os dados que você está procurando:
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Isto irá criar uma visão para mostrar a você os dados como se fosse uma tabela:
create or replace view t2
as
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Se você realmente precisa da mesa, você quer dizer que você precisa constantemente atualizado? ou apenas um fora? Obviamente, se ele é um fora de você pode apenas "criar tabela como selecionar" usando a consulta acima.
Test dados que usei é:
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;
edit:
esqueceu de acrescentar; você especificou que queria a tabela a ser ordenado - isso não faz muito sentido, e me faz pensar que você realmente quer dizer que você queria a consulta / vista - ordenação é um resultado da consulta que você executar, não é algo que está em inherant a mesa (ignorando Tabelas Índice organizado e afins).
Outras dicas
Vou começar com este importante caveate: Não criar uma tabela para armazenar esses dados. Quando você fizer isso você vai achar que você precisa para mantê-lo, que vai se tornar uma dor de cabeça sem fim. Escrever uma exibição para retornar a coluna extra se você quiser fazer isso. Se você está trabalhando com um armazém de dados, em seguida, talvez você faria algo como isso, mas mesmo assim errar do lado de uma vista a menos que você simplesmente não pode obter o desempenho que você precisa com índices, hardware decente, etc.
Aqui está uma consulta que irá retornar as linhas da maneira que você precisar deles.
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
Outra solução possível é:
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
Test-los tanto para o desempenho e ver o que funciona melhor para você. Além disso, eu não exaustivamente testado para além do exemplo que você deu, por isso não deixe de testar alguns casos extremos.
usar o Google Analytics, assim como em sua última pergunta:
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
/
saída:
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