代码之家  ›  专栏  ›  技术社区  ›  Zsolt Botykai

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

  •  6
  • Zsolt Botykai  · 技术社区  · 16 年前

    我有一张这样的桌子(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 回复  |  直到 16 年前
        1
  •  18
  •   William    16 年前

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

    这将为您获取所需的数据:

    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;
    

    编辑:

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

        2
  •  4
  •   Tom H    16 年前

    我将从一个非常重要的警告开始:不要创建一个表来保存这些数据。当你这样做的时候,你会发现你需要保持它,这将成为一个永无止境的头痛。如果要返回额外的列,请编写一个视图。如果您使用的是数据仓库,那么 大概

    下面是一个查询,它将按您需要的方式返回行。

    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
  •  4
  •   tuinstoel    16 年前

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

    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