如何跟踪账户的最小和最大余额

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

现在一切准备就绪,可以按帐户和月份进行简单的 MINMAX 聚合分组

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 表中的最小值/最大值?

如何识别 UISlider 的运动是从最大值到最小值,反之亦然?

PayPal IPN 账户跟踪,它是如何实现的?

SQL查询以跟踪新订单或旧订单中的余额变化,没有日期

用于成对比较和跟踪最大/最长序列的 STL 算法