2017-01-23 29 views
3

我有幾個帳戶賬戶負6個月或更無論交易

Select * from Trans; 

AccountID PostDate Description Amount 
1   07/01/2016 deposit  10.00 
1   07/09/2016 withdrawal -15.00 

第二帳戶:

AccountID PostDate Description Amount 
2   07/01/2016 deposit  10.00 
2   07/13/2016 withdrawal -20.00 
2   01/05/2017 deposit  8.00 

第三個帳戶:

AccountID PostDate Description Amount 
3   07/05/2016 deposit  10.00 
3   07/19/2016 deposit  20.00 
3   08/28/2016 withdrawal -45.00 

四帳號:

AccountID PostDate Description Amount 
4   01/05/2016 deposit  10.00 
4   01/19/2016 withdrawal -20.00 
4   09/28/2016 deposit  40.00 
4   10/01/2016 withdrawal -50 

我在尋找所有連續6個月以上爲負數的賬戶,無論存款是否存入,賬戶保持負值。如果存款使運行的餘額爲正,那麼顯然我需要排除該帳戶。

我需要一個通用的查詢......因爲我有超過上述兩個帳戶在trans表中。

查詢應該選擇AccountID 1,因爲它在180天以上爲負數。它應該從2016年7月13日起收取AccountID 2,因爲它是負值。 7月份爲負值-10,雖然有存款,但2017年1月仍保持負值-2。由於餘額爲負值,但在2016年8月28日爲負值,這意味着它不應收回AccountID 3只有148天爲負值。我也不想拿起賬戶'4'。雖然它連續6個月或更長時間爲負值,目前也是負值....但我想要在01/23/2017 - 07/23/2016之間的所有日子裏獲得運行餘額爲負值的帳戶。

謝謝

+0

「超過180天」是什麼意思?您是否需要從2013年7月至2015年1月選擇一個賬戶餘額爲1.5年的賬戶?或者只有具有負數*當前*餘額的賬戶(如'SYSDATE'),並且在過去的180天內總是有負數餘額? **另外**:您使用的是哪個版本的Oracle?不同的版本有不同的工具可用。 (如果你不知道,運行'select * from v $ version')。 – mathguy

+0

賬號3在桌面上有錯字嗎?看起來你顯示的是提取的負數和存款的正數,但對於賬戶3,你有20.00(正數)的提款和-45.00的存款,這是什麼意思? – mathguy

+0

是的。任何6個月或更長時間爲負值的帳戶,但目前需要爲負值。例如:2013年7月至2017年1月,帳戶「55」爲負數,我需要選擇該帳戶。但2013年7月至2016年12月期間爲負數的賬戶'66',但現在在2017年1月轉爲正數。我不想挑選它。我正在運行Oracle 12c。我在帳戶3中修正了錯字。謝謝 – Amir

回答

1

甲骨文設置

CREATE TABLE trans (AccountID, PostDate, Description, Amount) AS 
SELECT 1, DATE '2016-07-01', 'deposit',  10.00 FROM DUAL UNION ALL 
SELECT 1, DATE '2016-07-09', 'withdrawal', -15.00 FROM DUAL UNION ALL 
SELECT 2, DATE '2016-07-01', 'deposit',  10.00 FROM DUAL UNION ALL 
SELECT 2, DATE '2016-07-13', 'withdrawal', -20.00 FROM DUAL UNION ALL 
SELECT 2, DATE '2017-01-05', 'deposit',  8.00 FROM DUAL UNION ALL 
SELECT 3, DATE '2016-07-05', 'deposit',  10.00 FROM DUAL UNION ALL 
SELECT 3, DATE '2016-07-19', 'deposit',  20.00 FROM DUAL UNION ALL 
SELECT 3, DATE '2016-08-28', 'withdrawal', -45.00 FROM DUAL UNION ALL 
SELECT 4, DATE '2016-01-05', 'deposit',  10.00 FROM DUAL UNION ALL 
SELECT 4, DATE '2016-01-19', 'withdrawal', -20.00 FROM DUAL UNION ALL 
SELECT 4, DATE '2016-09-28', 'deposit',  40.00 FROM DUAL UNION ALL 
SELECT 4, DATE '2016-10-01', 'withdrawal', -50.00 FROM DUAL; 

查詢

SELECT accountid 
FROM (
    SELECT t.*, 
     SUM(amount) OVER (PARTITION BY AccountID ORDER BY postdate) 
      AS balance 
    FROM trans t 
) 
GROUP BY accountid 
HAVING MAX(balance) KEEP (DENSE_RANK LAST ORDER BY postdate) < 0 
AND ( MAX(postdate) <= TRUNC(SYSDATE) - 180 
     OR MAX(CASE WHEN postdate >= TRUNC(SYSDATE) - 180 
        THEN balance - amount END) < 0 
     ); 

輸出

ACCOUNTID 
---------- 
     1 
     2 
0

首先,你需要計算每一天的餘額。爲此,請使用累積和:

select t.*, 
     sum(amount) over (partition by accountid order by postdate) as balance 
from trans t; 

然後,您希望180天的餘額爲正數或負數。這很棘手。這裏是一個蠻力的方法:

with tb as (
     select t.*, 
      sum(amount) over (partition by accountid order by postdate) as balance 
     from trans t 
    ) 
select distinct accountid 
from tb 
where tb.balance < 0 and 
     not exists (select 1 
        from tb tb2 
        where tb2.accountid = tb.accountid and 
         tb2.balance > 0 and 
         tb2.postdate >= tb.postdate and tb2.postdate < tb.postdate + 180 
       ); 
0

這是一種解決這個MATCH_RECOGNIZE的方法。它假定PostDate可能沒有任何給定帳戶的重複。 (如果給定日期有多筆交易,交易時間將控制如何處理。)

關鍵是PATTERN子句。我們尋找一系列交易(包括一個賬戶的所有行,因爲我們使用^$來定位),其中前0行到(未知)行數不受約束(a行),然後我們查找一行( b),在trunc(SYSDATE)之前爲負值餘額且日期爲180天或更多,其餘所有行必須爲負餘額。

with 
    trans (AccountID, PostDate, Description, Amount) as ( 
     select 1, to_date('07/01/2016', 'mm/dd/yy'), 'deposit' , 10.00 from dual union all 
     select 1, to_date('07/09/2016', 'mm/dd/yy'), 'withdrawal', -15.00 from dual union all 
     select 2, to_date('07/01/2016', 'mm/dd/yy'), 'deposit' , 10.00 from dual union all 
     select 2, to_date('07/13/2016', 'mm/dd/yy'), 'withdrawal', -20.00 from dual union all 
     select 2, to_date('01/05/2017', 'mm/dd/yy'), 'deposit' , 8.00 from dual union all 
     select 3, to_date('07/05/2016', 'mm/dd/yy'), 'deposit' , 10.00 from dual union all 
     select 3, to_date('07/19/2016', 'mm/dd/yy'), 'deposit' , 20.00 from dual union all 
     select 3, to_date('08/28/2016', 'mm/dd/yy'), 'withdrawal', -45.00 from dual union all 
     select 4, to_date('01/05/2016', 'mm/dd/yy'), 'deposit' , 10.00 from dual union all 
     select 4, to_date('01/19/2016', 'mm/dd/yy'), 'withdrawal', -20.00 from dual union all 
     select 4, to_date('09/28/2016', 'mm/dd/yy'), 'deposit' , 40.00 from dual union all 
     select 4, to_date('10/01/2016', 'mm/dd/yy'), 'withdrawal', -50 from dual 
    ) 
-- End of test data; SQL query begins BELOW THIS LINE 
select AccountID 
from trans 
match_recognize(
    partition by AccountID 
    order  by PostDate 
    pattern (^ a* b c* $) 
    define b as b.PostDate <= trunc(sysdate) - 180 and sum(Amount) < 0, 
      c as          sum(Amount) < 0 
) 
; 

ACCOUNTID 
---------- 
     1 
     2 

2 rows selected. 
+0

如果帳戶在過去180天內已開立,並且負餘額打開,會發生什麼情況? – MT0

+0

@ mt0 - 我從OP的聲明中假設不應該包含這樣的賬戶。無論如何,它不包含在此查詢的輸出中。 – mathguy

+0

對不起,我只是意識到12c只處於較低的環境。將從現在起一個月過去。所以生產數據庫正在使用11G。 – Amir

0

你也可以試試這個片段。這也足以滿足你的要求。希望這可以幫助。

SELECT b.acc 
FROM 
    (SELECT row_number() over(partition BY a.acc order by dt DESC) nr, 
    SUM(a.amt) over(partition BY a.acc order by 1 DESC) sm, 
    row_number() over(partition BY a.acc,tp order by a.dt DESC) dt1, 
    a.* 
    FROM 
    (SELECT 1 acc, '2016-07-01' dt, 'deposit' tp, 10.00 amt FROM dual 
    UNION ALL 
    SELECT 1, '2016-07-09' dt, 'withdrawal' tp, -15.00 amt FROM dual 
    UNION ALL 
    SELECT 2, '2016-07-01' dt, 'deposit' tp, 10.00 amt FROM dual 
    UNION ALL 
    SELECT 2, '2016-07-13' dt, 'withdrawal' tp, -20.00 amt FROM dual 
    UNION ALL 
    SELECT 2, '2017-01-05' dt, 'deposit' tp, 8.00 amt FROM dual 
    UNION ALL 
    SELECT 3, '2016-07-05' dt, 'deposit' tp, 10.00 amt FROM dual 
    UNION ALL 
    SELECT 3, '2016-07-19' dt, 'deposit' tp, 20.00 amt FROM dual 
    UNION ALL 
    SELECT 3, '2016-08-28' dt, 'withdrawal' tp, -45.00 amt FROM dual 
    UNION ALL 
    SELECT 4, '2016-01-05' dt, 'deposit' tp, 10.00 amt FROM dual 
    UNION ALL 
    SELECT 4, '2016-01-19' dt, 'withdrawal' tp, -20.00 amt FROM dual 
    UNION ALL 
    SELECT 4, '2016-09-28' dt, 'deposit' tp, 40.00 amt FROM dual 
    UNION ALL 
    SELECT 4, '2016-10-01' dt, 'withdrawal' tp, -50.00 amt FROM dual 
    )a 
)b 
WHERE (b.nr          = 1 
OR b.dt1           =1) 
AND b.sm           < 0 
AND b.tp           <> 'deposit' 
AND (TRUNC(sysdate) - to_date(b.dt,'yyyy-mm-dd')) > 180;