Oracle MODEL clause giving unusual output

oracleoracle-12c

This is my table structure:

Name         Null Type        
------------ ---- ----------- 
PAID_MM           VARCHAR2(2) 
GA                NUMBER      
SA                NUMBER      
MA                NUMBER      
TOTAL_AMOUNT      NUMBER      
AMT_VAR           NUMBER  

and this is my data:

PAID_MM  GA     SA     MA     TOTAL_AMOUNT  AMT_VAR
01       98.5   48.16  161.47  308.13          0
02       116.34 53.14  115.46  284.94          0
03       288.03 25.31  136.04  449.38          0
04       138.41 118.84 148.5   405.75          0
05       75.69  190.74 51.7    318.13          0
06       451.18  0     214.84  666.02          0

I want calculate the AMT_VAR as (TOTAL_AMOUNT of current month – TOTAL_AMOUNT of previous month / TOTAL_AMOUNT of previous month) *100.

I am using Oracle MODEL clause as this:

SELECT 
  PAID_MM, 
  TOTAL_AMOUNT, 
  TRUNC(AMT_VAR*100, 2) AS VARIAN
FROM 
  AGNT_PAID_SUMM
MODEL RETURN UPDATED ROWS
DIMENSION BY (PAID_MM)
MEASURES (AMT_VAR, TOTAL_AMOUNT)
RULES 
(
AMT_VAR [PAID_MM] = ((TOTAL_AMOUNT[CV(PAID_MM)] - TOTAL_AMOUNT[CV(PAID_MM)      -1])/TOTAL_AMOUNT[CV(PAID_MM) -1])
)
ORDER BY PAID_MM

and I am getting the following output:

PAID_MM  TOTAL_AMOUNT VARIAN
01       308.13       NULL
02       284.94       NULL
03       449.38       NULL
04       405.75       NULL  
05       318.13       NULL  
06       666.02       NULL
07       339.47       NULL
08       445.86       NULL
09       548.52       NULL
10       363.94       NULL
11       362.8        -0.31
12       409.37       12.83

This looks quite weird to me. Can somebody help me understand why it's not working for all the rows except the last two ones?

I am using Oracle 12c.

Best Answer

The computed dimension expressions are false.
PAID_MM is a string (e.g. '03') but CV(PAID_MM)-1 is a number (e.g. 2, which is different from '02'), therefore you get NULL for your expressions, unless CV(PAID_MM)-1 has more than 1 digit and then you have no leading '0' to loose.

Here is working code which uses to_char(CV(PAID_MM)-1,'FM00') instead of CV(PAID_MM)-1:

SELECT 
  PAID_MM, 
  TOTAL_AMOUNT, 
  TRUNC(AMT_VAR*100, 2) AS VARIAN
FROM 
  AGNT_PAID_SUMM
MODEL RETURN UPDATED ROWS
DIMENSION BY (PAID_MM)
MEASURES (AMT_VAR, TOTAL_AMOUNT)
RULES 
(
AMT_VAR [PAID_MM] = ((TOTAL_AMOUNT[CV(PAID_MM)] - TOTAL_AMOUNT[to_char(CV(PAID_MM)-1,'FM00')])/TOTAL_AMOUNT[to_char(CV(PAID_MM)-1,'FM00')])
)
ORDER BY PAID_MM

+---------+--------------+--------+
| PAID_MM | TOTAL_AMOUNT | VARIAN |
+---------+--------------+--------+
| 01      | 308.13       | (null) |
+---------+--------------+--------+
| 02      | 284.94       | -7.52  |
+---------+--------------+--------+
| 03      | 449.38       | 57.71  |
+---------+--------------+--------+
| 04      | 405.75       | -9.7   |
+---------+--------------+--------+
| 05      | 318.13       | -21.59 |
+---------+--------------+--------+
| 06      | 666.02       | 109.35 |
+---------+--------------+--------+