我正在开发一个应用程序,我必须存储一些银行帐户信息,包括每日帐户余额。
所以,例如:
17/10/2014 - (+) - Starting/Initial balance - 5,000.00
17/10/2014 - (=) - Balance - 5,000.00
-
18/10/2014 - (-) - Payment - (1,000.00)
18/10/2014 - (=) - Balance - 4,000.00
-
19/10/2014 - (=) - Balance - 4,000.00
-
20/10/2014 - (-) - Payment - (1,000.00)
20/10/2014 - (=) - Balance - 3,000.00
我想我可以创建一个特定的" account_balance"我可以存储每天的每个帐户余额的表格。
如果我错了,你能帮我找到最好的方法吗?但是,如果我正确,如何让数据库计算每日余额,特别是,当用户开始编辑旧值时,如何使数据库更新余额?
通过"旧值",我的意思是:
1 - 这就是"账户A"声明如下:
18/10/2014 - (+) - Starting/Initial balance - 5,000.00
18/10/2014 - (=) - Balance - 5,000.00
-
19/10/2014 - (=) - Balance - 5,000.00
-
20/10/2014 - (=) - Balance - 5,000.00
2 - 但是用户忘了注册收入,所以他通过增加新收入来做到这一点(所以现在必须更新余额):
18/10/2014 - (+) - Starting/Initial balance - 5,000.00
18/10/2014 - (+) - Sales commission - 2,500.00 <- USER ADDED THIS.
18/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED.
-
19/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED.
-
20/10/2014 - (=) - Balance - 7,500.00 <- THIS BALANCE HAS BEEN UPDATED.
答案 0 :(得分:2)
不是存储余额,而是拥有一个仅为每个用户存储交易的表。
例如:
Date Transactions Comment
17/10/2014 +5,000.00 Starting/Initial balance -
18/10/2014 -1,000.00 Payment
20/10/2014 -1,000.00 Payment
然后你可以创建一个平衡视图(类似的东西):
create view balance as
select userId, sum(transactions) as balance from TransactionTable group by userId
如果您想更精确并包括开始和停止日期(即:能够在任何时间点获得余额),您可以创建parametrized view(避难所尝试使用它)日期,但我认为它也会起作用。)
答案 1 :(得分:1)
这个答案适用于PostgreSQL,OP在原始问题的评论中询问了这个问题。
数据完整性对我来说是最重要的。所以我不愿意存储聚合值,除非a)性能差,并且b)dbms可以保证聚合值是正确的。
我从这张桌子开始。
create table transactions (
trans_id serial primary key,
cust_id integer not null, -- foreign key, references customers, not shown
trans_time timestamp not null default current_timestamp,
trans_amt numeric(14,2) not null
);
create index on transactions (cust_id);
我选择了时间戳而不是日期,因为像这样的应用程序通常需要来支持时间戳,并且因为在一般情况下它应该比日期更差。如果我们通过时间戳获得良好的性能,我们应该能够通过日期获得良好的性能。我没想到单个客户的时间戳是唯一的。
我在这个表中加载了2000万行随机数据,然后我更新了统计数据。数据包括正数和负数。这笔金额甚至达到数百美元,使视觉检查更容易。
此类应用程序中较常见的查询之一涉及为单个客户返回一个注册表 - 所有具有运行余额的交易。
以下是前三天客户128的原始数据。
cust_id trans_time trans_amt -- 128 2014-01-01 08:36:09 200.00 128 2014-01-01 14:18:10 200.00 128 2014-01-01 14:26:56 0.00 128 2014-01-01 18:17:31 400.00 128 2014-01-01 20:18:53 100.00 128 2014-01-02 00:10:35 0.00 128 2014-01-02 01:44:26 300.00 128 2014-01-02 15:49:31 -300.00 128 2014-01-03 00:33:23 400.00 128 2014-01-03 11:55:13 -200.00 128 2014-01-03 11:56:34 -100.00 128 2014-01-03 14:58:42 -400.00 128 2014-01-03 17:31:11 0.00
前三天我们应该期待这些金额。
2014-01-01 900.00 2014-01-02 0.00 2014-01-03 -300.00
前三天的运行余额应如下所示。
2014-01-01 900.00 2014-01-02 900.00 2014-01-03 600.00
每日余额记录
select
cust_id
, trans_date
, sum(daily_amt) over (partition by cust_id order by trans_date) daily_balance
from (select
cust_id
, trans_time::date trans_date
, sum(trans_amt) daily_amt
from transactions
where cust_id = 128
group by cust_id, trans_date) x
order by cust_id, trans_date;
cust_id trans_date daily_balance -- 128 2014-01-01 900.00 128 2014-01-02 900.00 128 2014-01-03 600.00 . . .
注册的执行计划
执行计划显示上述查询在12毫秒内运行。我认为这种应用是合理的,但我可以通过索引表达式(trans_time::date
)或复合索引来减少12 ms以下的运行时间。
"WindowAgg (cost=7232.14..7252.94 rows=1040 width=40) (actual time=11.728..12.093 rows=294 loops=1)" " -> Sort (cost=7232.14..7234.74 rows=1040 width=40) (actual time=11.700..11.733 rows=294 loops=1)" " Sort Key: transactions.cust_id, ((transactions.trans_time)::date)" " Sort Method: quicksort Memory: 38kB" " -> HashAggregate (cost=7156.62..7169.62 rows=1040 width=16) (actual time=11.392..11.466 rows=294 loops=1)" " -> Bitmap Heap Scan on transactions (cost=39.66..7141.89 rows=1964 width=16) (actual time=0.839..9.753 rows=1961 loops=1)" " Recheck Cond: (cust_id = 128)" " -> Bitmap Index Scan on transactions_cust_id_idx (cost=0.00..39.17 rows=1964 width=0) (actual time=0.501..0.501 rows=1961 loops=1)" " Index Cond: (cust_id = 128)" "Total runtime: 12.272 ms"
答案 2 :(得分:1)
在我的情况下,是表架构
为此,我提供以下解决方案
SELECT id, user_id, credit, debit,
COALESCE(((SELECT SUM(credit) FROM user_transactions b WHERE b.id <= a.id AND user_id = '7') - (SELECT SUM(debit) FROM user_transactions b WHERE b.id <= a.id AND user_id = '7')), 0) as balance
FROM user_transactions a WHERE user_id = '7' ORDER BY id ASC;
这是希望对您有帮助的结果。