【问题标题】:Calculation of balance after each transaction每次交易后计算余额
【发布时间】:2013-08-28 17:35:53
【问题描述】:

我有这样的表:

cust_id acc_no trans_id  trans_type amount
1111    1001    10   credit     2000.0  
1111    1001    11   credit     1000.0
1111    1001    12   debit      1000.0  
2222    1002    13   credit     2000.0  
2222    1002    14   debit      1000.0

我想为客户完成的每笔交易使用 Hive 查询或 sql 查询,因此应计算余额。

我想要输出如下:

cust_id acc_no trans_id  trans_type amount      balance
1111.0  1001.0  10.0     credit    2000.0   2000.0
1111.0  1001.0  11.0     credit    1000.0   3000.0
1111.0  1001.0  12.0     debit     1000.0   2000.0
2222.0  1002.0  13.0     credit    2000.0   2000.0
2222.0  1002.0  14.0     debit     1000.0   1000.0

我试过了

SELECT * 
FROM   (SELECT cust_id, 
               acc_no, 
               trans_id, 
               trans_type, 
               amount, 
               CASE 
                 WHEN Trim(trans_type) = 'credit' THEN ball = 
                 Trim(bal) + Trim(amt) 
                 ELSE ball = Trim(bal) - Trim(amt) 
               end 
        FROM   ban) l; 

【问题讨论】:

  • 什么平台(PostgreSQL、SQL Server、MySQL)?为什么要将前 3 列的 int 类型转换为十进制?
  • 到目前为止你尝试过什么?
  • @FreshPrinceOfSO 我想要 sql 查询来计算余额。不要担心前 3 列都是 int only。
  • @basu 请用您尝试过的查询更新您的问题。
  • @FreshPrinceOfSO 我尝试使用此查询 select * from ( select cust_id,acc_no,trans_id,trans_type,amount, case when trim(trans_type)='credit' then ball=trim(bal)+trim( amt) else ball=trim(bal)-trim(amt) end from ban) l;

标签: sql


【解决方案1】:

这个查询可以解决问题:

SELECT t1.cust_id,t1.acc_no,t1.trans_id,t1.trans_type,t1.amount,
       sum(t2.amount*case when t2.trans_type = 'credit' then 1 
                             else -1 end) as balance
FROM Table1 t1
INNER JOIN Table1 t2 ON t1.cust_id = t2.cust_id AND 
                        t1.acc_no = t2.acc_no AND 
                        t1.trans_id >= t2.trans_id
GROUP BY t1.cust_id,t1.acc_no,t1.trans_id,t1.trans_type,t1.amount

请参阅 SQLFIDDLE:http://www.sqlfiddle.com/#!2/3b5d8/15/0

编辑: SQL Fiddle

MySQL 5.5.32 架构设置

CREATE TABLE Table1
    (`cust_id` int, `acc_no` int, `trans_id` int, 
     `trans_type` varchar(6), `amount` int)
;

INSERT INTO Table1
    (`cust_id`, `acc_no`, `trans_id`, `trans_type`, `amount`)
VALUES
    (1111, 1001, 10, 'credit', 2000.0),
    (1111, 1001, 11, 'credit', 1000.0),
    (1111, 1001, 12, 'debit', 1000.0),
    (2222, 1002, 13, 'credit', 2000.0),
    (2222, 1002, 14, 'debit', 1000.0)
;

查询 1

SELECT t1.cust_id,t1.acc_no,t1.trans_id,t1.trans_type,t1.amount,
       sum(t2.amount*case when t2.trans_type = 'credit' then 1 
                             else -1 end) as balance
FROM Table1 t1
INNER JOIN Table1 t2 ON t1.cust_id = t2.cust_id AND 
                        t1.acc_no = t2.acc_no AND 
                        t1.trans_id >= t2.trans_id
GROUP BY t1.cust_id,t1.acc_no,t1.trans_id,t1.trans_type,t1.amount

Results

| CUST_ID | ACC_NO | TRANS_ID | TRANS_TYPE | AMOUNT | BALANCE |
|---------|--------|----------|------------|--------|---------|
|    1111 |   1001 |       10 |     credit |   2000 |    2000 |
|    1111 |   1001 |       11 |     credit |   1000 |    3000 |
|    1111 |   1001 |       12 |      debit |   1000 |    2000 |
|    2222 |   1002 |       13 |     credit |   2000 |    2000 |
|    2222 |   1002 |       14 |      debit |   1000 |    1000 |

【讨论】:

  • 感谢您的回复,但问题是此查询将为我们提供总期末余额,但余额应按照我在表中提到的客户一个帐号完成的每笔交易计算
  • 不,它在每笔交易中都给出了余额...你看过 SQLFIDDLE 链接吗
  • 它给出了答案,如此cust_id arc_no trans_id trans_type金额余额1111 1001 10 rection 2000.0 2000 1111 1001 11信用1000.0 2000 1111 1001 12借记1000.0 2000 2222 1002 13信用2000.01000 2222 1002 14借记1.借记1.01010
  • 你确定吗?我看到:cust_id acc_no trans_id trans_type金额余额1111 1001 10 rective 2000.0 2000 1111 111111111111111111111111111111111111111111111111111111111111111111111111111112借款1000.0 2000 2000 2222 1002 13信用2000.0 2000 2222 1002 14借记1000.0 1000 span>
【解决方案2】:

您可以通过View 轻松完成此操作,直接在表上计算是可能的,但会导致性能和可伸缩性问题(数据库将随着表的增长而变慢)。通过使用View,根据需要执行计算;如果您为视图编制索引,则可以使余额保持最新,而不会影响事务表的性能。

如果您真的坚持将其放在交易表本身中,您可以使用计算列来运行用户定义的函数来确定当前余额。但是,这在很大程度上取决于您使用的特定 SQL 后端。


这是一个基本的 SELECT 语句,它按帐户计算当前余额:

select
acc_no, 
sum(case trans_type 
    when 'credit' then amount 
    when 'debit' then amount * -1 
    end) as Amount 
from Transactions
group by acc_no

【讨论】:

  • 请注意,索引视图是通向完整 OLAP 多维数据集的下一个逻辑步骤。
【解决方案3】:

您可以使用窗口功能:

select cust_id, 
acc_no, trans_id, trans_type, amount, 
sum(pre_balance) over (partition by cust_id order by trans_id) as balance
from    
(select cust_id, acc_no, trans_id, trans_type, 
        amount, 
        amount as pre_balance from test 
        where trans_type = 'credit' 
 union
 select cust_id, acc_no, trans_id, trans_type, 
        amount, -amount as pre_balance from 
        test where trans_type = 'debit'
 order by trans_id) as sub;

【讨论】:

    【解决方案4】:
    with current_balances as (
    SELECT
           id,
           user_id,
           SUM(amount) OVER (PARTITION BY user_id ORDER BY created ASC) as current_balance
    FROM payments_transaction pt
    ORDER BY created DESC
    )
    SELECT
        pt.id,
        amount,
        pt.user_id,
        cb.current_balance as running_balance
    FROM
        payments_transaction pt
    INNER JOIN
        current_balances cb
    ON pt.id = cb.id
    ORDER BY created DESC
    LIMIT 10;
    

    这将非常有效地获得大回报,并且不会因过滤或限制而中断。请注意,如果您只选择一个用户或其子集,请在 current_balances cte 和主选择中提供 user_id 过滤器以省略整个表扫描。

    【讨论】:

      【解决方案5】:

      一个简单的解决方案是根据trans_type对每笔交易(-或+)进行量化,然后使用窗口函数得到累积和。

      SELECT cust_id, 
         acc_no, 
         trans_id, 
         trans_type, 
         amount, 
         Sum (real_amount) 
           OVER (ORDER BY cust_id) AS balance 
      FROM   (SELECT cust_id, 
                 acc_no, 
                 trans_id, 
                 trans_type, 
                 amount, 
                 ( CASE trans_type 
                     WHEN 'credit' THEN amount 
                     WHEN 'debit' THEN amount *- 1 
                   END ) AS real_amount 
          FROM   test) t
      

      【讨论】:

        【解决方案6】:
        表(事务) - “id” “金额” “is_credit”

        1 10000 1
        2 2000 0
        3 5000 1

        查询:

        选择 * 从 ( SELECT id, amount, SUM(CASE When is_credit=1 Then amount Else -amount End) OVER (ORDER BY id) AS balance 来自“交易” GROUP BY id, 金额 ) ORDER BY id ;

        输出:

        “id”“金额”“is_credit”“余额”

        1 10000 1 10000

        2 2000 0 8000

        3 5000 1 13000

        【讨论】:

          猜你喜欢
          • 2020-11-15
          • 2015-11-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多