仅当余额为负3个月或更长时间时才进行帐户

时间:2017-01-20 00:39:25

标签: sql oracle function aggregate

Select * from Balance;

它有AccountID,ClosingDate和Balance。

每个月都有一个条目。例如:

AccountID   ClosingDate   Balance
123         1/19/2017     -3.00
123         12/19/2016    -2.50
123         11/19/2016    -2.50

另一个帐户

AccountID   ClosingDate   Balance
456         1/16/2017     -3.00
456         12/16/2016    2.00
456         11/16/2016    -2.50

最后一个例子:

AccountID   ClosingDate   Balance
789         1/11/2017     -9.00
789         12/11/2016    -2.00
789         11/11/2016    -5.50

我想编写一个查询,生成连续3个语句周期为负数的帐户列表。请记住,所有这些日期的截止日期都不同。查询不应该选择''''帐号。大约有100,000个账户是负面的。但是,我是否需要找到它们是否连续3个月都是负面的。

我需要帐号和最新余额作为输出。但是,如果查询最新的余额很困难,那么只需帐号即可。

由于

1 个答案:

答案 0 :(得分:1)

如果您的dbms支持窗口函数,请使用leadlag获取下一个和上一个余额first_value以获得每个值的最新余额。然后获得具有最新余额的帐户,其中当前行的余额,下一行的余额和前一行的余额为< 0

with cte as (select t.*, 
             lead(balance) over(partition by accountid order by closingdate) as next_balance,
             lag(balance) over(partition by accountid order by closingdate) as prev_balance,
             first_value(balance) over(partition by accountid order by closingdate desc) as latest_balance
             from t)
select distinct accountid, latest_balance
from cte
where balance < 0 and next_balance < 0 and prev_balance < 0  

编辑:解释它的工作原理。让我用你的样本数据来展示它。

123         1/19/2017     -3.00 --balance = -3.00, previous_balance = -2.50, next_balance = null
123         12/19/2016    -2.50 --balance = -2.50, previous_balance = -2.50, next_balance = -3.00
123         11/19/2016    -2.50 --balance = -2.50, previous_balance = null, next_balance = -2.50
  • where balance < 0 and next_balance < 0 and prev_balance < 0 - 2016年12月19日的行符合此指标连续3个月的负余额标准,并在结果中返回。
  • first_value(balance) over(partition by accountid order by closingdate desc) - 返回截至每个帐户最新日期的余额。

您可以使用此说明来了解它对其他accountid的作用。

Edit_2:要获得连续7个月或更长时间的负余额的帐户,请使用

WITH CTE AS
 (SELECT T.*,
         FIRST_VALUE(BALANCE) OVER(PARTITION BY ACCOUNTID ORDER BY CLOSINGDATE DESC) AS LATEST_BALANCE ,
         ROW_NUMBER() OVER(PARTITION BY ACCOUNTID ORDER BY CLOSINGDATE) - 
         ROW_NUMBER() OVER(PARTITION BY ACCOUNTID, SIGN(BALANCE) ORDER BY CLOSINGDATE) AS GRP
  FROM T
  )
 ,COUNTS AS
 (SELECT C.*,
         SUM(CASE WHEN BALANCE < 0 THEN 1 ELSE 0 END) OVER(PARTITION BY ACCOUNTID,GRP ORDER BY CLOSINGDATE) AS CONSECUTIVE_COUNT
  FROM CTE C
  )
SELECT DISTINCT ACCOUNTID, LATEST_BALANCE
FROM COUNTS
WHERE CONSECUTIVE_COUNT >= 7

或者,如果您准备编写冗长的查询,请使用leadlag函数中的可选参数来向前看或回顾n行。在这里,您回顾并向前看每行3行。

with cte as (select t.*, 
             lead(balance,1) over(partition by accountid order by closingdate) as next_balance_1,
             lead(balance,2) over(partition by accountid order by closingdate) as next_balance_2,
             lead(balance,3) over(partition by accountid order by closingdate) as next_balance_3,
             lag(balance,1) over(partition by accountid order by closingdate) as prev_balance_1,
             lag(balance,2) over(partition by accountid order by closingdate) as prev_balance_2,
             lag(balance,3) over(partition by accountid order by closingdate) as prev_balance_3,
             first_value(balance) over(partition by accountid order by closingdate desc) as latest_balance
             from t)
select distinct accountid, latest_balance
from cte
where balance < 0 
and next_balance_1 < 0 and next_balance_2 < 0 and next_balance_3 < 0
and prev_balance_1 < 0 and prev_balance_2 < 0 and prev_balance_3 < 0