按表中的分组记录运行总计

Posted

技术标签:

【中文标题】按表中的分组记录运行总计【英文标题】:Running total by grouped records in table 【发布时间】:2010-10-01 03:33:32 【问题描述】:

我有一张这样的表(Oracle,10)

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

我需要的是按 Account order by Account asc 和 Bookdate asc 分组的新表,其中包含一个运行总计字段,如下所示:

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

有简单的方法吗?

提前致谢。

【问题讨论】:

为什么不提供创建表脚本?这样可以更轻松地回答您的问题。 由于都是伪表,我们假设它们是很简单的建表脚本,但如果真的有必要,我可以根据上面的数据生成... 【参考方案1】:

使用分析,就像在上一个问题中一样:

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

【讨论】:

我需要该表用于备份。谢谢你的回答,我明天试试。 – Zsolt 我相信 mysql 不支持分析。我不知道。我不知道如何在 MySQL 中做一个运行总计。【参考方案2】:

你真的需要额外的桌子吗?

您可以通过一个简单的查询获得所需的数据,如果您希望它看起来像一个表格,您显然可以将其创建为一个视图。

这将为您提供您正在寻找的数据:

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;

编辑:

忘记添加了;您指定要对表进行排序-这实际上没有意义,并且让我认为您的真正意思是您想要查询/视图-排序是您执行的查询的结果,而不是固有的东西表(忽略索引组织表等)。

【讨论】:

我需要该表用于备份。谢谢你的回答,我明天试试。【参考方案3】:

我将从这个非常重要的警告开始:不要创建一个表来保存这些数据。当你这样做时,你会发现你需要维护它,这将成为一个永无止境的头痛。如果您想这样做,请编写一个视图以返回额外的列。如果您使用的是数据仓库,那么也许您会做这样的事情,但即便如此,除非您根本无法通过索引获得所需的性能,否则还是会在视图方面犯错,不错的硬件等。

这是一个查询,它将以您需要的方式返回行。

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

测试它们的性能,看看哪个更适合您。此外,除了您提供的示例之外,我还没有对它们进行彻底测试,因此请务必测试一些边缘情况。

【讨论】:

确实不需要表格,如果性能非常非常重要,可能需要物化视图。 我需要该表用于备份。谢谢你的回答,我明天试试。 – Zsolt

以上是关于按表中的分组记录运行总计的主要内容,如果未能解决你的问题,请参考以下文章

按月、年分组的数据集运行总计

从运行总计 (SQL) 雪花中排除某些记录

在cshtml中分组

SQL Server Reporting Services 在聚合数据上运行总计

Spring数据存储库按列分组,包含其他列的对象列表

BigQuery:按表名分组