sqldb2db2-400db2-luw

How to calculate churn Rate (Retention) in db2?


Here are info I have: Group Name /YYYYMM / Contracts. Now I need the last 12 months churn rate and SQL runs efficiently.

I wrote this , but not working properly:

SELECT GROUP_NAME,ID, YRMO,SUM(FLOAT(CTC)) AS CTC_MOS,
MAX(CASE WHEN YRMO = VARCHAR_FORMAT(DATE(TO_DATE(@ENR_END_INC,'YYYYMM'))- 12 MONTHS, 'YYYYMM') THEN VARCHAR_FORMAT(DATE(TO_DATE(@ENR_END_INC,'YYYYMM'))- 12 MONTHS, 'YYYYMM') END)  AS YRMO_PRIOR,
SUM(CASE WHEN YRMO = VARCHAR_FORMAT(DATE(TO_DATE(@ENR_END_INC,'YYYYMM'))- 12 MONTHS, 'YYYYMM') THEN CTC END)  AS CTC_PRIOR

FROM TABLE1

below is sample data if needed:

GP  YRMO    CTC
B1  202011  8
B1  202012  10
B1  202101  11
B1  202102  11
B1  202103  11
B1  202104  11
B1  202105  12
B1  202106  12
B1  202107  12
B1  202108  12
B1  202109  12
B1  202110  12
B1  202111  12
B1  202112  11
B1  202201  11
B1  202202  11
B1  202203  11
B1  202204  13
B1  202205  14
B1  202206  15
B1  202207  22
B1  202208  23
B1  202209  23
B1  202210  23
B1  202211  24
B1  202311  27

How can I produce something like below: enter image description here


Solution

  • The solution without JOIN.

    WITH T (GP, YRMO, CTC) AS
    (
      VALUES
      ('B1', 202011, 8)
    , ('B1', 202012, 10)
    , ('B1', 202111, 12)
    , ('B1', 202112, 11)
    , ('B1', 202211, 24)
    , ('B1', 202212, 0)
    )
    SELECT 
      T.*
    , COALESCE (100 * (CTC_C - CTC_P) / NULLIF (CTC_P, 0), 100)
      AS RATE 
    FROM
    (
    SELECT 
      GP, YRMO
    , CTC AS CTC_C
    , YRMO - 100 AS YRMO_P
    , COALESCE (LAG (CTC) OVER (PARTITION BY GP, MOD (YRMO, 100) ORDER BY YRMO), 0)
      AS CTC_P
    FROM T
    ) T
    ORDER BY GP, YRMO
    
    GP YRMO CTC_C YRMO_P CTC_P RATE
    B1 202011 8 201911 0 100
    B1 202012 10 201912 0 100
    B1 202111 12 202011 8 50
    B1 202112 11 202012 10 10
    B1 202211 24 202111 12 100
    B1 202212 0 202112 11 -100

    fiddle

    Update:

    For 6-month you may use the following expressions:

    , INT (TO_CHAR (TO_DATE (VARCHAR (YRMO) || '01', 'YYYYMMDD') - 6 MONTH, 'YYYYMM'))
      AS YRMO_P
    , COALESCE
      (
        MAX (CTC) OVER 
        (
          PARTITION BY GP
          ORDER BY MOD (YRMO, 100) + (YRMO / 100) * 12
          RANGE BETWEEN 6 PRECEDING AND 6 PRECEDING 
        )
      , 0
      ) AS CTC_P
    

    The idea is to enumerate months sequentially without gaps with the ORDER BY expression to use RANGE inside MAX () OVER ().