Reputation: 171
While i execute below query
SELECT (TO_NUMBER (TO_CHAR ('25-07-19', 'YYYY')) - 1) + CEIL
(
CASE
WHEN (MONTHS_BETWEEN ( LAST_DAY ( TO_DATE ( TO_CHAR ('18-05-2020', 'DD/MM/YYYY'), 'DD-MM-YYYY')), LAST_DAY ('25-07-19')))>0 THEN
MONTHS_BETWEEN ( LAST_DAY ( TO_DATE ( TO_CHAR ('18-05-2020', 'DD/MM/YYYY'), 'DD-MM-YYYY')), LAST_DAY ('25-07-19'))
ELSE 1 END / 12) Year
FROM dual;
Am getting returns error as below
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
Upvotes: 0
Views: 161
Reputation: 167972
Your error comes from calling TO_CHAR
, such as:
TO_CHAR ('25-07-19', 'YYYY')
or
TO_CHAR ('18-05-2020', 'DD/MM/YYYY')
The TO_CHAR
function is overloaded and the first argument can either be a number or a date; you have supplied neither and passed in a string so Oracle is attempting to implicitly convert '25-07-19'
and '18-05-2020'
to numbers, since it does not know that you want it to be a date. You should not rely on implicit conversions.
Instead you could explicitly convert your string to a date:
TO_CHAR ( TO_DATE( '18-05-2020', 'DD-MM-YYYY' ), 'DD/MM/YYYY')
But, better would be to use a date literal DATE '2020-05-18'
or, if you are immediately going to convert it to a string again then just supply the string in the correct format.
So, you can simplify your function a lot by eliminating the TO_CHAR
calls and replacing most of TO_DATE
calls with date literals. Similarly, you don't need to use TO_NUMBER( TO_CHAR( date_value, 'YYYY' ) )
and can instead use EXTRACT
. You can also replace your CASE
statement with GREATEST
.
Which gets you to a much simpler query:
SELECT EXTRACT( YEAR FROM DATE '2019-07-25' )
- 1
+ CEIL(
GREATEST(
MONTHS_BETWEEN(
LAST_DAY( DATE '2020-05-18' ),
LAST_DAY( DATE '2019-07-25' )
),
1
) / 12
) AS Year
FROM DUAL;
Which outputs:
| YEAR | | ---: | | 2019 |
db<>fiddle here
Upvotes: 1
Reputation: 43574
You have to convert the string values with date to a date datatype first, using TO_DATE
:
SELECT (TO_NUMBER (TO_CHAR (TO_DATE('25-07-19', 'DD-MM-YY'), 'YYYY')) - 1) + CEIL
(
CASE WHEN (
MONTHS_BETWEEN(LAST_DAY(TO_DATE('18-05-2020', 'DD-MM-YYYY')), LAST_DAY(TO_DATE('25-07-19', 'DD-MM-YY')))) > 0 THEN
MONTHS_BETWEEN(LAST_DAY(TO_DATE('18-05-2020', 'DD-MM-YYYY')), LAST_DAY (TO_DATE('25-07-19', 'DD-MM-YY')))
ELSE 1 END / 12) Year
FROM dual;
Upvotes: 0
Reputation: 3653
You can try this:
SELECT (TO_NUMBER(TO_CHAR(TO_DATE('25-07-19', 'DD-MM-YY'), 'YYYY')) - 1) +
CEIL (
CASE
WHEN (MONTHS_BETWEEN(LAST_DAY(TO_DATE('18-05-2020', 'DD-MM-YYYY')), LAST_DAY(TO_DATE('25-07-19','DD-MM-YY')))) > 0 THEN
MONTHS_BETWEEN(LAST_DAY(TO_DATE('18-05-2020', 'DD-MM-YYYY')), LAST_DAY(TO_DATE('25-07-19','DD-MM-YY')))
ELSE 1
END / 12) YEAR
FROM dual;
Upvotes: 0