如何跟踪账户的最小和最大余额
Posted
技术标签:
【中文标题】如何跟踪账户的最小和最大余额【英文标题】:How to Track Min and Max Balance of an Account 【发布时间】:2021-02-23 15:48:54 【问题描述】:我正在研究跟踪银行账户的最高和最低余额。有两个表:
AccountBalanceHistoryTable - 记录每个月末每个账户的余额
TransactionTable - 这记录了一个帐户上发生的所有交易
我创建了以下查询以将这两个表放在一起以获得运行余额,然后我将使用该查询从中选择最大和最小余额:
select
i.acct_id,
i.trnxamt,
i.date_trnx,
EXTRACT (MONTH from i.date_trnx) month_num,
EXTRACT (YEAR from i.date_trnx) as year_num,
(
j.balance + sum(i.trnxamt) over (partition by i.acct_id order by i.date_trnx ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)
) as balance_calc
from
TransactionTable i
left join (
select
acct_id,
monthend_date,
balance,
row_number() over (partition by acct_id order by monthend_date) as rn
from
AccountBalanceHistoryTable
) j on i.acct_id = j.acct_id
and j.rn = 1
我使用 AccountBalanceHistoryTable 获取我看到记录的一个月的最后余额(第一行),并将其作为下个月的起始余额。
假设在 AccountBalanceHistoryTable 中显示,对于帐户 123456,8 月 31 日的余额为 100 美元。以下仅显示了一些示例交易以及 Balance_Calc 将计算的内容:
Acct_ID | TrnxAmnt | Date_Trnx | Month_num | Year_num | Balance_Calc |
---|---|---|---|---|---|
123456 | -55 | 29-Sep-20 | 9 | 2020 | 45 |
123456 | 10 | 30-Sep-20 | 9 | 2020 | 55 |
123456 | 100 | 1-Oct-20 | 10 | 2020 | 155 |
123456 | 20 | 1-Oct-20 | 10 | 2020 | 175 |
我遇到的问题是,上面说是 10 月 1 日。在此帐户 10 月份发生任何交易之前,期初余额为 55 美元(9 月 30 日的期末余额)。这 55 美元实际上应该是我 10 月的最低余额,但如果我使用上表并选择 2020 年 10 月的最低和最高余额,它将给我 155 美元的最低余额和 175 美元的最高余额,因为这是仅有的两个上述子查询结果中显示的记录。
【问题讨论】:
开始的一般问题:您是否真的需要查看每月期末余额表?无论如何都不能从事务表中计算出来吗?如果是这样,那么仅基于事务表进行所有计算可能会更容易(也更有效)。我可以告诉你如何(很多人可以告诉你如何),但首先请确认这实际上是正确的。 @MarmiteBomber - 这就是我问的原因。至少在“先进”国家,在“信誉良好”的银行,通常会保存从账户开始的完整交易历史,即使在数据仓库中的计算通常基于上个月的期末余额。如果 OP 无论如何都需要查看单个事务(因为他必须执行他的任务),这意味着他必须查看单个事务。或者,我们需要每个帐户一个期初余额,而不是每个月的期初余额。 另一个需要澄清的问题。您的数据仅显示交易日期(无时间部分)。这是正确的,还是交易记录在一天中的时间?无论哪种方式 - 两个交易可以同时发生吗?如果是这样,你如何处理计算余额?除非您在计算新余额之前汇总它们,否则您将有歧义。例如,在同一笔交易中存款 30 和取款 20(相同的时间戳) - 是否显示为单笔存款 10?如果不是,您是先加 30 还是先减 20 来计算滚动余额? @Marmite Bomber - 这非常有效 - 非常感谢。只是为了我自己的学习,使用“With”语句有什么好处?据我所知,它只是让查询更简单一些?我想同样的事情可以用单独的选择语句来完成,然后两者之间的联合(即一个用于余额历史记录和一个用于交易)? @Marmite Bomber - 另外 - 我想我理解解码语句的用途 - 基本上是为 AccountBalanceHistoryTable 中的记录分配“1”,为 TransactionTable 中的记录分配“2”如果在余额历史记录的同一天有交易,订购目的是什么?我应该提到交易日期通常有一个与之相关的时间戳,但我很高兴这无论如何都能正常工作。再次感谢! 【参考方案1】:诀窍是将月末午夜的余额转移到下个月的 1 日。
这是余额表的例子
select * from AccountBalanceHistory
where acct_id = 123456
order by monthend_date;
ACCT_ID MONTHEND_DATE BALANCE
---------- ------------------- ----------
123456 31.08.2020 00:00:00 100
123456 30.09.2020 00:00:00 55
123456 31.10.2020 00:00:00 175
还有你的交易表
select * from Transaction
where acct_id = 123456
order by date_trnx;
ACCT_ID DATE_TRNX TRNXAMT
---------- ------------------- ----------
123456 29.09.2020 00:00:00 -55
123456 30.09.2020 00:00:00 10
123456 01.10.2020 00:00:00 100
123456 01.10.2020 00:00:00 20
unions下面的查询是两个来源并计算交易月份,这是下个月1号的余额。
请注意,每一行都有它的来源 BAL 或 TX - 这将用于正确排序行
with tx as (
select 'BAL' source, acct_id, monthend_date date_trnx, trunc(monthend_date+1,'MM') tx_month, balance, 0 trnxamt from AccountBalanceHistory
union all
select 'TX', acct_id, date_trnx,trunc(date_trnx,'MM') tx_month, trnxamt balance, trnxamt from Transaction
)
select *
from tx
where acct_id = 123456
order by date_trnx;
SOU ACCT_ID DATE_TRNX TX_MONTH BALANCE TRNXAMT
--- ---------- ------------------- ------------------- ---------- ----------
BAL 123456 31.08.2020 00:00:00 01.09.2020 00:00:00 100 0
TX 123456 29.09.2020 00:00:00 01.09.2020 00:00:00 -55 -55
TX 123456 30.09.2020 00:00:00 01.09.2020 00:00:00 10 10
BAL 123456 30.09.2020 00:00:00 01.10.2020 00:00:00 55 0
TX 123456 01.10.2020 00:00:00 01.10.2020 00:00:00 20 20
TX 123456 01.10.2020 00:00:00 01.10.2020 00:00:00 100 100
BAL 123456 31.10.2020 00:00:00 01.11.2020 00:00:00 175 0
balance
列包含余额或交易金额,在我们添加之前不是很有趣
使用每个月的分析窗口函数(从月初到当前行)
with tx as (
select 'BAL' source, acct_id, monthend_date date_trnx, trunc(monthend_date+1,'MM') tx_month, balance, 0 trnxamt from AccountBalanceHistory
union all
select 'TX', acct_id, date_trnx,trunc(date_trnx,'MM') tx_month, trnxamt balance, trnxamt from Transaction
)
select
SOURCE, ACCT_ID, DATE_TRNX, TX_MONTH,
sum(BALANCE) over (partition by ACCT_ID,TX_MONTH order by date_trnx, decode (SOURCE,'BAL',1,'TX',2), trnxamt desc) as BALANCE,
TRNXAMT
from tx
where acct_id = 123456
order by date_trnx;
SOU ACCT_ID DATE_TRNX TX_MONTH BALANCE TRNXAMT
--- ---------- ------------------- ------------------- ---------- ----------
BAL 123456 31.08.2020 00:00:00 01.09.2020 00:00:00 100 0
TX 123456 29.09.2020 00:00:00 01.09.2020 00:00:00 45 -55
TX 123456 30.09.2020 00:00:00 01.09.2020 00:00:00 55 10
BAL 123456 30.09.2020 00:00:00 01.10.2020 00:00:00 55 0
TX 123456 01.10.2020 00:00:00 01.10.2020 00:00:00 155 100
TX 123456 01.10.2020 00:00:00 01.10.2020 00:00:00 175 20
BAL 123456 31.10.2020 00:00:00 01.11.2020 00:00:00 175 0
现在一切准备就绪,可以按帐户和月份进行简单的 MIN
和 MAX
聚合分组
with tx as (
select 'BAL' source, acct_id, monthend_date date_trnx, trunc(monthend_date+1,'MM') tx_month, balance, 0 trnxamt from AccountBalanceHistory
union all
select 'TX', acct_id, date_trnx,trunc(date_trnx,'MM') tx_month, trnxamt balance, trnxamt from Transaction
), tx2 as (
select
SOURCE, ACCT_ID, DATE_TRNX, TX_MONTH,
sum(BALANCE) over (partition by ACCT_ID,TX_MONTH order by date_trnx, decode (SOURCE,'BAL',1,'TX',2), trnxamt desc) as BALANCE,
TRNXAMT
from tx
where acct_id = 123456)
select acct_id, TX_MONTH, min(BALANCE), max(BALANCE)
from tx2
group by acct_id, TX_MONTH
order by 1,2;
ACCT_ID TX_MONTH MIN(BALANCE) MAX(BALANCE)
---------- ------------------- ------------ ------------
123456 01.09.2020 00:00:00 45 100
123456 01.10.2020 00:00:00 55 175
123456 01.11.2020 00:00:00 175 175
【讨论】:
以上是关于如何跟踪账户的最小和最大余额的主要内容,如果未能解决你的问题,请参考以下文章
Stroustrup C++ 书籍。如何跟踪while循环中哪个整数输入最小和最大?
是否可以通过单个查询跟踪 DynamoDB 表中的最小值/最大值?