Промежуточный итог по сгруппированным записям в таблице - PullRequest
9 голосов
/ 13 января 2009

У меня есть такая таблица (Oracle, 10)

Account     Bookdate     Amount
      1     20080101        100
      1     20080102        101
      2     20080102        200
      1     20080103       -200
...

Что мне нужно, так это новая таблица, сгруппированная по порядку счета по учетной записи asc и Bookdate asc с полем итоговой суммы, например:

Account     Bookdate     Amount     Running_total
      1     20080101        100               100
      1     20080102        101               201
      1     20080103       -200                 1
      2     20080102        200               200
...

Есть ли простой способ сделать это?

Заранее спасибо.

Ответы [ 3 ]

15 голосов
/ 13 января 2009

Вам действительно нужен дополнительный стол?

Вы можете получить необходимые данные с помощью простого запроса, который, очевидно, можно создать в виде представления, если хотите, чтобы он отображался в виде таблицы.

Это даст вам данные, которые вы ищете:

select 
    account, bookdate, amount, 
    sum(amount) over (partition by account order by bookdate) running_total
from t
/

Это создаст представление для отображения данных, как если бы они были таблицей:

create or replace view t2
as
select 
    account, bookdate, amount, 
    sum(amount) over (partition by account order by bookdate) running_total 
from t
/

Если вам действительно нужна таблица, вы имеете в виду, что она нужна вам постоянно обновляться? или только один раз? Очевидно, что если он один, вы можете просто «создать таблицу как выбор», используя приведенный выше запрос.

Данные испытаний, которые я использовал:

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;

редактирование:

забыл добавить; вы указали, что хотите, чтобы таблица была упорядочена - это на самом деле не имеет смысла, и заставляет меня думать, что вы действительно имеете в виду, что вы хотели запрос / представление - упорядочение является результатом выполняемого вами запроса, а не чем-то, что является неотъемлемым таблица (игнорируя индексные организованные таблицы и т. п.).

4 голосов
/ 13 января 2009

Я начну с этого очень важного предостережения: НЕ создавайте таблицу для хранения этих данных. Когда вы это сделаете, вы обнаружите, что вам нужно поддерживать его, что станет постоянной болью. Напишите представление для возврата дополнительного столбца, если вы хотите это сделать. Если вы работаете с хранилищем данных, тогда , возможно, , вы бы сделали что-то подобное, но даже в этом случае вы ошибаетесь, если вы просто не можете получить нужную производительность с индексами, приличную аппаратное обеспечение и т. д.

Вот запрос, который вернет строки так, как вам нужно.

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

Другое возможное решение:

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

Проверьте их обе на производительность и посмотрите, какая из них лучше для вас. Кроме того, я не проверил их полностью, кроме приведенного вами примера, поэтому обязательно протестируйте некоторые крайние случаи.

3 голосов
/ 13 января 2009

Используйте аналитику, как в вашем последнем вопросе:

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
/

выход:

   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
...