Exécution du total par enregistrements groupés dans la table
-
22-07-2019 - |
Question
J'ai une table comme celle-ci (Oracle, 10)
Account Bookdate Amount
1 20080101 100
1 20080102 101
2 20080102 200
1 20080103 -200
...
Ce dont j'ai besoin, c’est d’une nouvelle table groupée par ordre de compte, par compte, asc et compte, et Bookdate, asc avec un champ de total cumulé, comme ceci:
Account Bookdate Amount Running_total
1 20080101 100 100
1 20080102 101 201
1 20080103 -200 1
2 20080102 200 200
...
Existe-t-il un moyen simple de le faire?
Merci d'avance.
La solution
Avez-vous vraiment besoin de la table supplémentaire?
Vous pouvez obtenir les données dont vous avez besoin avec une requête simple, que vous pouvez évidemment créer en tant que vue si vous souhaitez qu'elle apparaisse comme une table.
Cela vous donnera les données que vous recherchez:
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Ceci créera une vue pour vous montrer les données comme s'il s'agissait d'un tableau:
create or replace view t2
as
select
account, bookdate, amount,
sum(amount) over (partition by account order by bookdate) running_total
from t
/
Si vous avez vraiment besoin de la table, voulez-vous dire que vous avez besoin de la mettre à jour en permanence? ou juste un seul? Évidemment, si c'est un cas isolé, vous pouvez simplement "créer une table en tant que sélectionner". en utilisant la requête ci-dessus.
Les données de test que j'ai utilisées sont:
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;
modifier:
a oublié d'ajouter; vous avez indiqué que vous vouliez que la table soit ordonnée - cela n'a pas vraiment de sens et me fait penser que vous vouliez vraiment dire que vous vouliez la requête / vue - l'ordre est le résultat de la requête que vous exécutez, pas quelque chose qui est inhérent à la table (en ignorant les tables organisées par index, etc.).
Autres conseils
Je commencerai par cet important problème: ne créez PAS de table pour stocker ces données. Quand vous le ferez, vous constaterez que vous devez le maintenir, ce qui deviendra un mal de tête sans fin. Ecrivez une vue pour renvoyer la colonne supplémentaire si vous voulez le faire. Si vous travaillez avec un entrepôt de données, alors peut-être vous feriez quelque chose comme ceci, mais même dans ce cas, vous vous tromperiez du côté d'une vue, à moins que vous n'obteniez tout simplement pas les performances dont vous avez besoin avec les index, matériel convenable, etc.
Voici une requête qui renvoie les lignes de la manière dont vous en avez besoin.
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
Une autre solution possible est la suivante:
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
Testez leurs performances et voyez ce qui vous convient le mieux. De plus, je ne les ai pas complètement testés au-delà de l'exemple que vous avez donné. Veillez donc à tester certains cas critiques.
Utilisez l'analyse, comme dans votre dernière question:
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
/
sortie:
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