Date with conversion function gives error in oracle - sql

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.

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

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;

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;
demo on dbfiddle.uk

Related

SQL ORA-01861: literal does not match format string

I have the following end of code on SQL (Oracle 19c)
WHERE DATE >= '20220101' AND DATE BETWEEN add_months(trunc(sysdate,'mm'),-1) AND last_day (add_months(trunc(sysdate,'mm'),-1)) AND DATE != 'None' AND QT_MOCK_DATA IS NOT NULL ORDER BY DATE DESC'
ERROR:
ORA-01861: literal does not match format string
Can someone help?
Thanks!
Column name certainly isn't date; it is reserved word, reserved for the datatype name. So, no - you don't have that code.
Next: it seems you are storing strings into that column (as you're comparing it to 'None', which is a string). That's a bad idea - dates should be stored as dates. Anything else brings problems (you hit one).
Then, you're comparing that string to date values. How come? The between part of the code returns date datatype values:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> SELECT ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1) val1,
2 LAST_DAY (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1)) val2
3 FROM DUAL;
VAL1 VAL2
------------------- -------------------
01.06.2022 00:00:00 30.06.2022 00:00:00
SQL>
Maybe you wanted to apply the TO_CHAR function with appropriate format model?
SQL> SELECT TO_CHAR (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1), 'yyyymmdd') val1,
2 TO_CHAR (LAST_DAY (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1)),
3 'yyyymmdd') val2
4 FROM DUAL;
VAL1 VAL2
-------- --------
20220601 20220630
SQL>
Because, with it, query returns something.
Compare
your code
SQL> WITH test (date1, qt_mock_data) AS (SELECT '20220615', 'A' FROM DUAL)
2 SELECT *
3 FROM test
4 WHERE date1 >= '20220101'
5 AND date1 BETWEEN ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1)
6 AND LAST_DAY (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1))
7 AND date1 != 'None'
8 AND qt_mock_data IS NOT NULL
9 ORDER BY date1 DESC;
WHERE date1 >= '20220101'
*
ERROR at line 4:
ORA-01861: literal does not match format string
to my code
SQL> WITH test (date1, qt_mock_data) AS (SELECT '20220615', 'A' FROM DUAL)
2 SELECT *
3 FROM test
4 WHERE date1 >= '20220101'
5 AND date1 BETWEEN TO_CHAR (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1),
6 'yyyymmdd')
7 AND TO_CHAR (
8 LAST_DAY (ADD_MONTHS (TRUNC (SYSDATE, 'mm'), -1)),
9 'yyyymmdd')
10 AND date1 != 'None'
11 AND qt_mock_data IS NOT NULL
12 ORDER BY date1 DESC;
DATE1 Q
-------- -
20220615 A
SQL>
I don't know your DB's schema. Maybe try using date literal?
WHERE
DATE >= date '20220101'
AND DATE BETWEEN add_months(
trunc(sysdate, 'mm'),
-1
)
AND last_day (
add_months(
trunc(sysdate, 'mm'),
-1
)
)
AND DATE != 'None'
AND QT_MOCK_DATA IS NOT NULL
ORDER BY
DATE DESC
Do not store dates as string, use a DATE data type (and do not use reserved words such as DATE as an identifier).
However, since you are storing the values as dates then convert the value you are comparing to to a string using TO_CHAR:
WHERE "DATE" >= '20220101'
AND "DATE" >= TO_CHAR(add_months(trunc(sysdate,'mm'),-1), 'YYYYMMDD')
AND "DATE" < TO_CHAR(trunc(sysdate,'mm'), 'YYYYMMDD')
AND "DATE" != 'None'
AND QT_MOCK_DATA IS NOT NULL
ORDER BY "DATE" DESC
which can be simplified to:
WHERE "DATE" >= TO_CHAR(add_months(trunc(sysdate,'mm'),-1), 'YYYYMMDD')
AND "DATE" < TO_CHAR(trunc(sysdate,'mm'), 'YYYYMMDD')
AND QT_MOCK_DATA IS NOT NULL
ORDER BY "DATE" DESC
(Since the start of the range will, assuming SYSDATE is not set to a past dates, always be greater than 20220101 and if the date range is valid then != 'None' will always also be true.)

How to find the first date of a month from a given datetime dataset (in SQL Oracle)?

Does any in-built function exists for that please?
I've created this one;
to_char( add_months( ( last_day( sysdate ) + 1 ), -1 ), 'dd/mm/yyyy' )
Thanks in advance. Chri$
You can use TRUNC() with a date format argument:
select trunc(sysdate, 'MON') from dual

DATE Manipulation

I would appreciate any pointers with this, I'm trying to ultimately get the Day of the week for each date. Unfortunately my DATESTRG in format 02-JUL-13 is ending up as 13/07/0002 rather than 02-07-2013 ( European date format ), and I get an error when I try to get the Day of Week DOW. Thank you.
WITH DATEDATE AS
(
SELECT
SUBSTR ( SRT.CREATED_DATE,1,10) AS DATESTRG
FROM SMS.REVIEW_TEXT SRT
)
SELECT
DATESTRG,
TO_DATE ( DATESTRG, 'YYYY-MM-DD' )
TO_CHAR ( DATE DATESTRG, 'DY') AS DOW
FROM DATEDATE
Try this:
WITH DATEDATE AS
(
SELECT
SUBSTR ( '2017-09-08',1,10) AS DATESTRG
FROM dual
)
SELECT
TO_CHAR (to_date(DATESTRG,'YYYY-MM-DD'), 'DY') AS DOW
FROM DATEDATE

get first day of a given week number in oracle

Please help to derive first day of a given week_no in oracle not from given date.
You can try following query:-
SELECT NEXT_DAY(MAX(d), 'SUN') REQUESTED_SUN
FROM (SELECT TO_DATE('01-01-2015', 'DD-MM-YYYY') + (ROWNUM-1) d FROM DUAL CONNECT BY LEVEL <= 366)
WHERE TO_CHAR(d, 'WW') = Your_Desired_WEEK_NO-1;
This might be helpful to you.
Use this query
Select TRUNC (Trunc(sysdate,'yyyy')+(:num-1)*7,'IW') from duaL;
:num is number of week from year 2015, or put year what you need instead of sysdate.
You can use this function to get the date of the ISO week:
CREATE FUNCTION TO_ISO_WEEK_DATE(
week NUMBER,
year NUMBER
) RETURN DATE DETERMINISTIC
IS
BEGIN
RETURN NEXT_DAY(
TO_DATE( TO_CHAR( year, '0000' ) || '0104', 'YYYYMMDD' )
- INTERVAL '7' DAY, 'MONDAY'
)
+ ( week - 1 ) * 7;
END TO_ISO_WEEK_DATE;
/

Insert date in oracle

When i executed the below query in Oracle
select TO_CHAR((CURRENT_DATE),'DD-Mon-YYYY HH24:MI:SS') from dual;
O/P : 04-Mar-2014 14:25:14
I would like to select current date only without current time as below
select TO_CHAR(trunc(CURRENT_DATE),'DD-Mon-YYYY HH24:MI:SS') from dual;
O/P : 04-Mar-2014 00:00:00
To achieve the only way is to apply function trunc() on the query? Is there any another way?
Edit : Thanks for your ans.Can it be done without any function?(wihout using to_char or trunc)
{sorry for missing this info}
The answer is simply no, there is no function that only gets the date part of the date / time (even current_date or sysdate are functions after all).
You should always use trunc to get the current date, without the time.
It isn't necessary to do a trunc and a to_char together. Keep to_char and don't specify the time part.
This is sufficient:
To get the date as varchar:
select TO_CHAR(CURRENT_DATE,'DD-Mon-YYYY') from dual
To get the date as date, with the time part as 00:00:00:
select trunc(CURRENT_DATE) from dual
You can do this:
select TO_CHAR(CURRENT_DATE,'DD-Mon-YYYY')||' 00:00:00' from dual;
there is also EXTRACT function which can be used like that:
SELECT extract(DAY FROM sysdate)
||'-' ||
extract(MONTH FROM sysdate)
|| '-' || extract(YEAR FROM sysdate)
FROM dual;
result: 4-3-2014
Use This Query...
select (TO_CHAR(TRUNC(CURRENT_DATE),'DD-Mon-YYYY HH24:MI:SS')) from dual