【问题标题】:Return account balances only if a date is greater than 30 days in the past仅当日期超过过去 30 天时才返回帐户余额
【发布时间】:2015-02-24 01:50:52
【问题描述】:

我有表accounts,在account_ID 列中有客户ID,在account_balance 列中每个ID 有多个帐户余额。每个 ID 也有多个语句日期,列 account_statement_date

如果账户余额大于 50.00 美元并且最近的对帐单日期超过 30 天,我需要返回 ID 和账户余额。

如果账户余额大于 50.00 美元,这将返回 ID 和账户余额:

select account_ID, sum(account_balance)
from accounts
where account_balance > 50
group by account_ID

如果帐户余额大于 50.00 美元并且最近的对帐单日期大于过去 30 天,我如何优化查询以仅返回 ID 和帐户余额?

【问题讨论】:

  • 对于account_id 的特定值,帐户余额是否等于account_balance 列中值的SUM()?我认为不需要汇总帐户余额。
  • 因此您只需要给定帐户的最新 account_balance。您只需要最近余额超过 50 美元且自对帐单日期起已过去 30 天的那些?
  • 你的桌子的布局是什么? account_statement_date 是帐户内的列吗?是在不同的桌子上吗?
  • 请参阅my answer below 并提供样本数据(与我的相似,但准确地代表您的数据)以及该数据集的正确答案。尝试提供有助于排除边缘情况的“棘手数据”,以更清楚地定义所需的业务规则。随意复制和粘贴。

标签: sql oracle


【解决方案1】:

只需在查询中添加having 子句:

select account_ID, sum(account_balance)
from accounts
where account_balance > 50
group by account_ID
having max(account_statement_date) < sysdate - 30;

编辑:

Shankar 的评论似乎是正确的。以下修复它:

select account_ID,
        sum(case when account_balance > 50 then account_balance else 0 end)
from accounts
group by account_ID
having max(account_statement_date) < sysdate - 30;

【讨论】:

  • 这行不通,因为在问题中他说一个帐户可以有多个余额。因此,当您执行 where account_balance > 50 时,它可以消除几行。比如acc1有2个余额,25和30,总共是55,需要显示出来,但是使用上面的查询时会完全消除acc1。
  • 我认为您希望 &lt; 在您的 HAVING 子句中(每个 OP“过去 30 天以上”)。
  • @DavidFaber 。 . .当我第一次阅读它时,我发现“过去 30 天以上”是模棱两可的(是一个 date 晚于过去 30 天,还是那个“日期”早于 30 天在过去)。重读一遍,好像我原来的解释是不正确的。
  • 是的,它确实似乎有点模棱两可......“超过 30 天”可能是更好的表达方式。
【解决方案2】:

我不确定您是否应该合计帐户余额。

SELECT * FROM (
    SELECT account_id, account_balance, account_statement_date
         , MAX(account_statement_date) OVER ( PARTITION BY account_id ) AS max_statement_date
      FROM accounts
) WHERE account_balance > 50
    AND account_statement_date = max_statement_date
    AND max_statement_date < TRUNC(SYSDATE-30);

【讨论】:

    【解决方案3】:

    如果您的数据如下所示:

    account_ID  account_statement_date  account_balance
    1529        2014-12-01              $40.00
    1529        2015-01-01              $60.00
    1529        2015-02-01              $65.00 -- < 30 days
    2647        2014-12-01              $20.00
    2647        2015-01-01              $25.00 -- > 30 days but < $50
    3198        2014-12-01              $10.00
    3198        2015-01-01              $50.00 -- > 30 days and >= $50
    

    2015-02-01 上运行时的正确答案是:

    account_ID  account_statement_date  account_balance
    3198        2015-01-01              $50.00
    

    那么我认为您想要的查询可能如下所示:

    SELECT
       a.account_ID,
       a.account_statement_date,
       a.account_balance
    FROM
       (
          SELECT
             row_number() OVER (PARTITION BY account_ID ORDER BY account_statement_date DESC) AS latest,
             account_ID,
             account_statement_date,
             account_balance
          FROM
             accounts
       ) AS a
    WHERE
       a.account_statement_date < sysdate - 30
       AND a.latest = 1
       AND a.account_balance >= 50
    ;
    

    但是,如果您的数据如下所示:

    account_ID  account_balance_date account_statement_date  account_balance
    1529        2014-12-10           2015-01-01              $40.00
    1529        2015-12-16           2015-01-01              $60.00
    1529        2015-01-10           2015-02-01              $30.00
    1529        2015-01-19           2015-02-01              $65.00 -- < 30 days
    2647        2014-12-25           2015-01-01              $20.00
    2647        2014-12-30           2015-01-01              $25.00 -- > 30 days
    2647        2014-01-02           NULL                    $75.00
    2647        2014-01-15           NULL                    $20.00 -- but < $50
    3198        2014-12-14           2015-01-01              $20.00
    3198        2014-12-30           2015-01-01              $25.00 -- > 30 days
    3198        2014-01-09           NULL                    $20.00
    3198        2014-01-22           NULL                    $50.00 -- and >= $50!
    

    2015-02-01 上运行时的正确答案是:

    account_ID  last_account_statement_date  last_account_balance
    3198        2015-01-01                   $50.00
    

    那么我认为您想要的查询可能如下所示:

    SELECT
       a.account_ID,
       a.account_balance AS last_account_balance,
       (
          SELECT Max(account_statement_date)
          FROM accounts a3
          WHERE
             a1.account_ID = a3.account_ID
             AND account_statement_date IS NOT NULL
       ) AS last_statement_date
    FROM
       (
          SELECT
             row_number() OVER (PARTITION BY account_ID ORDER BY account_balance_date DESC) AS latest,
             account_ID,
             account_balance_date,
             account_statement_date,
             account_balance
          FROM
             accounts
       ) AS a
     WHERE
        a.latest = 1 -- the most recent balance by account_balance_date
        AND a.account_balance >= 50
        AND ( -- this clause is optional and may aid or harm performance
           a.account_statement_date IS NULL
           OR a.account_statement_date < sysdate - 30
        )
        AND NOT EXISTS ( -- no statement in the last 30 days
           SELECT *
           FROM
              accounts AS a2
           WHERE
              a.account_ID = a2.accountID
              AND a2.account_statement_date >= sysdate - 30
        )
    ;
    

    我对 30 天部分持怀疑态度 - 可能是正确的计算将涉及从上一个报表日期开始的“一个月”的一些日期数学,并有已知的规则来确定不同月份的月份意味着什么天数。

    【讨论】:

    • 您在 cmets 中提到过,但您从未真正检查过那里的 50 美元要求。
    • 谢谢!那个更好吗?最后我很着急,错过了。
    • 我只是想我会提到它,因为 OP 可能不清楚在哪里添加它。而且我认为从技术上讲,OP 要求严格大于而不是大于或等于,但这在我的书中并不重要。
    • 我刚刚注意到一件更大的事情:如果我们已经知道 a.account_balance 日期是最新的报表日期,则没有理由进行子查询。
    • 我第一次考虑添加类似的东西,但我不喜欢引入复杂的 OR 条件。我现在把它加上一个关于它的可选性质的符号。 “大于 50 美元”与口语短语“18 岁以上”相同,意思是这个人至少 18 岁。
    【解决方案4】:

    我认为这应该适合你..

    select * from
    (select account_ID, sum(account_balance) bal, max(account_statement_date) st_date
    from accounts
    group by account_ID) tab1
    where tab1.bal > 50 and tab1.st_date > (sysdate - 30)
    

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 1970-01-01
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      • 2017-03-20
      • 2018-08-25
      • 2011-10-31
      • 1970-01-01
      相关资源
      最近更新 更多