Home > Back-end >  SQL: Generate Record Per Month for 1st of every month In Date Range
SQL: Generate Record Per Month for 1st of every month In Date Range

Time:01-14

I have below source table - TEST_TAB

DP_AD_ACCT_NBR DP_AD_CCY_CDE DP_AD_CURR_BAL DP_AD_LST_MDFSN_DATE
10001 REL123 100 2014-11-18
10001 REL123 174 2018-03-04
10001 REL123 145 2022-12-21
10001 REL123 150 2022-12-26
10001 REL123 96 2023-01-01
10001 REL123 80 2023-01-04

I want to print transaction for 1st of each month until next transaction happens, output should look like below

DP_AD_ACCT_NBR DP_AD_CCY_CDE DP_AD_CURR_BAL DP_AD_LST_MDFSN_DATE
10001 REL123 100 2014-11-18
10001 REL123 100 2014-12-01
10001 REL123 100 2015-01-01
10001 REL123 100 2015-02-01
... ... ... ...
10001 REL123 100 2018-03-01
10001 REL123 174 2018-03-04
10001 REL123 174 2018-04-01
... ... ... ...
10001 REL123 174 2022-11-01
10001 REL123 174 2022-12-01
10001 REL123 145 2022-12-21
10001 REL123 150 2022-12-26
10001 REL123 96 2023-01-01
10001 REL123 80 2023-01-04

I tried with below query but not getting expected answer

WITH TMP_TAB
  AS (SELECT DP_AD_ACCT_NBR, DP_AD_CCY_CDE,DP_AD_CURR_BAL, 
      TO_DATE(DP_AD_LST_MDFSN_DATE, 'MM/DD/YY') AS START_DATE, 
       LEAD(DP_AD_LST_MDFSN_DATE) OVER (PARTITION BY T.DP_AD_ACCT_NBR,T.DP_AD_CCY_CDE ORDER BY DP_AD_LST_MDFSN_DATE)AS END_DATE 
       FROM TEST_TAB
     )
SELECT DP_AD_ACCT_NBR, DP_AD_CCY_CDE,DP_AD_CURR_BAL,
     , TO_CHAR(ADD_MONTHS(start_date, level -1), 'MONTH') AS NAME_MONTH
     , TO_CHAR(ADD_MONTHS(start_date, level -1), 'YYYY')  AS NAME_YEAR
  FROM TMP_TAB
 CONNECT BY level <=  TO_NUMBER(TO_CHAR(end_date, 'MM') - TO_CHAR(start_date, 'MM'))            -- Month Difference
                      12 * TO_NUMBER((TO_CHAR(end_date, 'YYYY') - TO_CHAR(start_date, 'YYYY'))) -- Year Difference
                      1

CodePudding user response:

You can use a recursive query:

WITH generate_months (
  DP_AD_ACCT_NBR,
  DP_AD_CCY_CDE,
  DP_AD_CURR_BAL,
  DP_AD_LST_MDFSN_DATE,
  next_date
) AS (
  SELECT t.*,
         LEAD(DP_AD_LST_MDFSN_DATE)
           OVER (
             PARTITION BY DP_AD_ACCT_NBR, DP_AD_CCY_CDE
             ORDER BY DP_AD_LST_MDFSN_DATE
           )
  FROM   test_tab t
UNION ALL
  SELECT DP_AD_ACCT_NBR,
         DP_AD_CCY_CDE,
         DP_AD_CURR_BAL,
         ADD_MONTHS(TRUNC(DP_AD_LST_MDFSN_DATE, 'MM'), 1),
         next_date
  FROM   generate_months
  WHERE  ADD_MONTHS(TRUNC(DP_AD_LST_MDFSN_DATE, 'MM'), 1) < next_date
)
SEARCH DEPTH FIRST BY DP_AD_ACCT_NBR, DP_AD_CCY_CDE, DP_AD_LST_MDFSN_DATE
  SET order_id
SELECT DP_AD_ACCT_NBR,
       DP_AD_CCY_CDE,
       DP_AD_CURR_BAL,
       DP_AD_LST_MDFSN_DATE
FROM   generate_months;

Which, for the sample data:

CREATE TABLE test_tab (DP_AD_ACCT_NBR, DP_AD_CCY_CDE, DP_AD_CURR_BAL, DP_AD_LST_MDFSN_DATE) AS
SELECT 10001, 'REL123', 100, DATE '2014-11-18' FROM DUAL UNION ALL
SELECT 10001, 'REL123', 174, DATE '2018-03-04' FROM DUAL UNION ALL
SELECT 10001, 'REL123', 145, DATE '2022-12-21' FROM DUAL UNION ALL
SELECT 10001, 'REL123', 150, DATE '2022-12-26' FROM DUAL UNION ALL
SELECT 10001, 'REL123',  96, DATE '2023-01-01' FROM DUAL UNION ALL
SELECT 10001, 'REL123',  80, DATE '2023-01-04' FROM DUAL;

Outputs:

DP_AD_ACCT_NBR DP_AD_CCY_CDE DP_AD_CURR_BAL DP_AD_LST_MDFSN_DATE
10001 REL123 100 2014-11-18 00:00:00
10001 REL123 100 2014-12-01 00:00:00
10001 REL123 100 2015-01-01 00:00:00
10001 REL123 100 2015-02-01 00:00:00
... ... ... ...
10001 REL123 100 2018-02-01 00:00:00
10001 REL123 100 2018-03-01 00:00:00
10001 REL123 174 2018-03-04 00:00:00
10001 REL123 174 2018-04-01 00:00:00
... ... ... ...
10001 REL123 174 2022-11-01 00:00:00
10001 REL123 174 2022-12-01 00:00:00
10001 REL123 145 2022-12-21 00:00:00
10001 REL123 150 2022-12-26 00:00:00
10001 REL123 96 2023-01-01 00:00:00
10001 REL123 80 2023-01-04 00:00:00

fiddle

  • Related