ORA-01861 error on NUMBER(8) column - sql

I have the following SQL, which basically checks whether the "SYSDATE" fits in between specific dates(i.e. some date <= SYSDATE <= some date + 30 days).
TO_DATE(TO_CHAR(SYSDATE, 'YYYYMMDD')) BETWEEN TO_DATE(TO_CHAR(T1.WEB_STR_DT, 'YYYYMMDD')) AND
TO_DATE(TO_CHAR(T1.WEB_STR_DT, 'YYYYMMDD')) + 30
The problem I am facing is that I get ORA-01861 even the date is in the valid date format(yyyymmdd).
What could be the cause of this error?

You shouldn't be converting sysdate to and from a string at all, as that is wasteful but is also doing implicit conversion - which is what is causing the ORA-018611 error. Your NLS_DATE_FORMAT is not YYYYMMDD; you explicitly convert the date to that format, then try to convert the resulting string back to a date using whatever your NLS settings currently are:
select to_date(to_char(sysdate, 'YYYYMMDD')) from dual;
ORA-01861: literal does not match format string
select to_date(to_char(sysdate, 'YYYYMMDD'), 'YYYYMMDD') from dual;
TO_DATE(T
---------
13-APR-17
But instead of that you can just use trunc(sysdate). That strips the time back to midnight, so it would match if WEB_STR_DT represented today.
That isn't the only problem though. You shouldn't be storing dates as numbers in the first place, but if you must convert a number like 20170413 to a date then you need to convert it to a string first and then convert that string to a date.
Essentially you have your parentheses in the wrong place, and instead of
TO_DATE(TO_CHAR(T1.WEB_STR_DT, 'YYYYMMDD'))
you should have:
TO_DATE(TO_CHAR(T1.WEB_STR_DT), 'YYYYMMDD')
Your code is doing the equivalent of:
select to_date(to_char(20170413, 'YYYYMMDD')) from dual;
ORA-01481: invalid number format model
because you're attempting to use date format model elements to convert a number to a string. With that parenthesis moved you do end up with the equivalent date.
So, you can do:
TRUNC(SYSDATE) BETWEEN TO_DATE(TO_CHAR(T1.WEB_STR_DT), 'YYYYMMDD')
AND TO_DATE(TO_CHAR(T1.WEB_STR_DT), 'YYYYMMDD') + 30
Even the explicit TO_CHAR() calls are a bit unnecessary, since you aren't supply a format model for those, so even simpler would be:
TRUNC(SYSDATE) BETWEEN TO_DATE(T1.WEB_STR_DT, 'YYYYMMDD')
AND TO_DATE(T1.WEB_STR_DT, 'YYYYMMDD') + 30

Number conversion issues (and what is to_chat?)... I assume you just want date with no time.
Try TRUNC:
WHERE trunc(sysdate) between trunc(T1.WEB_STR_DT) and trunc(T1.WEB_STR_DT)+30

Related

Adding a day in Oracle but losing hour and minute, and format is also changing

I have a table tab1 in which a column col1 has data type VARCHAR2(50 BYTE) and this column has values like '9/27/21 18:05'
I want to add 1 day to this and I am expecting a result like '9/28/21 18:05'
If I do
TO_TIMESTAMP(col1,'MM/DD/YYYY HH24:MI') + INTERVAL '1' DAY
then I get '28-SEP-21 06.24.00.000000000 PM', and if I do
TO_DATE(col1,'MM/DD/YYYY HH24:MI') + INTERVAL '1' DAY'
then I get '28-SEP-21'.
Please note in both the above cases format is changing.
How can I get the result I want?
DATE and TIMESTAMP values are both binary data types that do NOT have a given format; therefore, when you convert a string to a DATE or a TIMESTAMP then the format you use is NOT stored.
If you want to convert it to a DATE or TIMESTAMP and then back to a string in the same format then, after adding the interval, you want to use TO_CHAR to convert back to a string with the required format.
For example:
SELECT TO_CHAR(
TO_DATE(col1, 'MM/DD/RR HH24:MI') + INTERVAL '1' DAY,
'MM/DD/RR HH24:MI'
)
FROM tab1
Note: If you use YYYY in the format model then 21 will be parsed as 21 AD and not as 2021 AD. Instead, you need to use YY or RR (depending on how you want values from the end of the last century to be handled).
Please note in both the above cases format is changing.
The format of your column is not changing, you have converted the strings to DATE and TIMESTAMP which are binary data type and do not have any format.
The user interface you are using (i.e. SQL/Plus or SQL Developer) tries to be helpful and rather than presenting you, the user, with binary data will use its internal rules to format the binary data as something you can read. SQL/Plus and SQL Developer will use the NLS_DATE_FORMAT session parameter for DATE values and the NLS_TIMESTAMP_FORMAT session parameter for TIMESTAMP values. These parameters can be set to different values for each user in each of their sessions so you should not rely on them to be consistent.
If you want a consistent format then wrap the date/timestamp in TO_CHAR to apply that consistent format.
You are converting your string into a date or timestamp, and adjusting it by a day. Your client then decides how to format that for display, usually using you session setting like NLS_DATE_FORMAT.
If you want to display (or store*) the value in a particular format then you should specify that, with to_char(), e.g.:
TO_CHAR(TO_DATE(col1,'MM/DD/YYYY HH24:MI') + INTERVAL '1' DAY,'MM/DD/YYYY HH24:MI')
09/28/0021 18:05
or if you want to suppress some leading zeros to match your original string you can toggle those with the FM modifier:
TO_CHAR(TO_DATE(col1,'MM/DD/YYYY HH24:MI') + INTERVAL '1' DAY,'FMMM/DD/YYYY HH24:FMMI')
9/28/21 18:05
As you can see in the output of first of those, and as #Aitor mentioned, the year comes out as 0021 rather than 21. That's because you used a four-digit YYYY mask for a 2-digit year value. In the second one the FM suppresses that, so it's less obvious. As you don't seem to care about the century it usually doesn't matter whether you use YY or RR - the exception maybe being if you happen to hit a leap year/day; but it's still better to have the mask match the string, so with RR:
TO_CHAR(TO_DATE(col1,'MM/DD/RR HH24:MI') + INTERVAL '1' DAY,'FMMM/DD/RR HH24:FMMI')
9/28/21 18:05
db<>fiddle
* But you should not be storing dates as strings. They should be stored as dates, and formatted as strings for display only. You shouldn't really be using 2-digit years any more either.
You said your column has this: 9/27/21, but you put a mask like YYYY. Be careful with that, because with YYYY, the year will be 21 BC...
Maybe you want RRRR in your date mask. RRRR means 2-digit years in the range 00 to 49 are assumed to be in the current century:
select to_char(to_date('9/27/2021 18:05','MM/DD/RRRR HH24:MI')+ INTERVAL '1' DAY,'MM/DD/YYYY HH24:MI') result
from dual;
Result: 09/28/2021 18:05
I don't know what is your output format, but anyway, if you want your date formatted like VARCHAR, try this. With your column, is something like that
select to_char(to_date(col1,'MM/DD/RRRR HH24:MI') + 1,'MM/DD/YYYY HH24:MI') result
from your_table;
Also you can use, instead of INTERVATL '1' DAY, a simple +1

PL SQL - Convert timestamp to datetime/date

select
to_timestamp(SCHEDULED_TIME,'YYYY-MM-DD HH24:MI:SS.FF') as SCHEDULED_TIME,
TRUNC(to_date(to_timestamp(SCHEDULED_TIME,'YYYY-MM-DD HH24:MI:SS.FF'),'YYYY-MM-DD HH24:MI:SS'))
from S_TIDAL_STATUS
The error was:
ORA-01830: date format picture ends before converting entire input string
01830. 00000 - "date format picture ends before converting entire input string"
The goal is to return something like
2017-07-91 23:14:00
(without the content after the dot).
Here's what the SCHEDULED_TIME (timestamp) looked like:
The problem in your attempt is the function TO_DATE() applied to a timestamp. TO_DATE() takes a VARCHAR2 (string) input, not a timestamp. So Oracle converts the timestamp to a string first, implicitly, using your NLS_TIMESTAMP_FORMAT parameter, and then attempts to convert this string to a date. Depending on your NLS_TIMESTAMP_FORMAT, you may get different errors.
The way to convert a timestamp to a date (datetime) - while truncating off the fractions of a second - is with the CAST function. Example:
select systimestamp,
cast (systimestamp as date) as ts_cast_to_date
from dual
;
Alternatively, if all your strings are EXACTLY in that format, you can truncate the strings first and apply TO_DATE directly:
to_date(substr(scheduled_time, 1, 19), 'yyyy-mm-dd hh24:mi:ss')
This should do the trick:
select
to_char(SCHEDULED_TIME,'YYYY-MM-DD HH24:MI:SS.FF') as time_to_csecs,
to_char(SCHEDULED_TIME,'YYYY-MM-DD HH24:MI:SS') as time_to_secs,
TRUNC(to_date(to_char(SCHEDULED_TIME,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')) as time_to_day
from S_TIDAL_STATUS
Please review the docs to see the difference between to_timestamp and to_char.

Questions on To_Date function

I have two questions,
1.
Why can't I get HH24:MI:SS when using To_date function?
select To_date(fn_adjusted_date(SUBMIT_DATE),'DD-MON-YY-HH24:MI:SS')
from HPD_Help_Desk;
16-NOV-08
select To_char(fn_adjusted_date(submit_date),'DD-MON-YY-HH24:MI:SS')
from HPD_Help_Desk;
16-NOV-08-06:01:10
2.
Why am I getting an error when using:
To_date(fn_adjusted_date(SUBMIT_DATE),'DD-MON-YY-HH24:MI:SS')
but changing it works fine when I change it to:
To_date(fn_adjusted_date(SUBMIT_DATE),'DD-MM-YY-HH24:MI:SS')
To demonstrate:
select sysdate from dual;
03-MAR-15
alter session set nls_date_format = 'dd-mm-yyyy hh24:mi:ss';
select sysdate from dual;
03-03-2015 11:29:22
select To_date(fn_adjusted_date(SUBMIT_DATE),'DD-MON-YY-HH24:MI:SS')
from HPD_Help_Desk;
ORA-01843: not a valid month 01843. 00000 - "not a valid month"
select To_char(fn_adjusted_date(submit_date),'DD-MON-YY-HH24:MI:SS')
from HPD_Help_Desk;
16-NOV-08-06:01:10
1.
Because to_date() gives you a date object, and you're leaving it up to your client to decide how to display that as a string; it's likely to be using your NLS_DATE_FORMAT settings.
Since your fn_adjusted_date() function returns a date not a string, do not then call to_date() on that; you're doing an implicit conversion to a string and then back to a date, both using NLS_DATE_FORMAT, and from how your first query is displayed - as DD-MON-YY? - that is losing the time portion anyway. So you're really doing:
select to_date(to_char(fn_adjusted_date(SUBMIT_DATE), 'DD-MON-YY'),
'DD-MON-YY-HH24:MI:SS') from HPD_Help_Desk;
2.
Because MON is the abbreviated month name in your date language. This follows on from the first point; now in the first of those you're doing an implicit to_char() of your value using the new NLS_DATE_FORMAT, which specifies the month number with MM, but then you try to convert that back to a date with MON. So this time you're really doing:
select to_date(to_char(fn_adjusted_date(SUBMIT_DATE), 'dd-mm-yyyy hh24:mi:ss'),
'DD-MON-YY-HH24:MI:SS') from HPD_Help_Desk;
And 11 is not a valid month name. Oracle is quite flexible with date formats when it can be; it can interpret 'NOV' using the MM model even though that doesn't make sense really since it isn't a number, but the meaning is pretty obvious; from your example in a comment:
select to_date('16-Nov-2008', 'DD-MM-YY') from dual;
TO_DATE('16-NOV-2008','DD-MM-YY')
---------------------------------
16-NOV-2008 00:00:00
It doesn't work the other way though; it can't interpret 11 using MON. That flexibility can appear inconsistent, and it sometimes seems to be too forgiving.
In the second query you're doing an explicit to_char() with a format model specified, which is the correct way to display a date as a string.
The underlying messages are the same for both: don't call to_date() when you already have a date object, don't ever rely on implicit conversion, and don't convert a date to a string while you're still processing it - only if you want it as a string in a specific format in your final result set.

Formatting value of year from SYSDATE

I want to insert the current date into one of the columns of my table. I am using the following:
to_date(SYSDATE, 'yyyy-mm-dd'));
This is working great, but it is displaying the year as '0014'. Is there some way that I can get the year to display as '2014'?
Inserting it as TRUNC(sysdate) would do. Date actually doesn't have a format internally as it is DataType itself. TRUNC() actualy will just trim the time element in the current date time and return today's date with time as 00:00:00
To explain what happened in your case.
say ur NLS_DATE_FORMAT="YY-MM-DD"
The Processing will be like below
select to_date(to_char(sysdate,'YY-MM-DD'),'YYYY-MM-DD') from dual;
Output:
TO_DATE(TO_CHAR(SYSDATE,'YY-MM-DD'),'YYYY-MM-DD')
January, 22 0014 00:00:00+0000
2014 - gets reduced to '14' in first to_char() and later while converted again as YYYY.. it wil be treated as 0014 as the current century detail is last!
to_date is used to convert a string to a date ... try to_char(SYSDATE, 'yyyy-mm-dd') to convert a date to a string.
The to_date function converts a string to a date. SYSDATE is already a date, so what this will do is to first convert SYSDATE to a string, using the session's date format as specified by NLS settings, and then convert that string back to date, using your specified date format (yyyy-mm-dd). That may or may not give correct results, depending on the session's NLS date settings.
The simple and correct solution is to skip the to_date from this and use SYSDATE directly.
Try this to_date(SYSDATE, 'dd-mm-yy')

oracle sql query giving error

Following query is giving error:
SELECT to_char(last_day(add_months(to_char(to_date('01-02-2013','dd-mm-yyyy'),
'dd-MON-yyyy'),-1)) + 1,'dd-mm-yyyy') FROM dual;
ORA-01858: a non-numeric character was found where a numeric was expected
I tried this on two systems:
with NLS_DATE_FORMAT='DD-MON-RR' - this query works fine.
With NLS_DATE_FORMAT='MM-DD-YYYY' - gives me error ORA-01858: a non-numeric character was found where a numeric was expected.
Any clues as to why this query is failing? I can't have the queries be dependent on the DATE format.
Why are you doing a to_char when calling add_months , you need to pass a date like
SELECT to_char(last_day(add_months(to_date('01-02-2013','dd-mm-yyyy'),
,-1)) + 1,'dd-mm-yyyy') FROM dual;
You have an implicit char-to-date conversion, in the add_months() call; the argument you're passing is a string, not a date. The to_char() you have inside that is redundant, and causing the error when your NLS_DATE_FORMAT doesn't match the format you're using in that to_char():
SELECT to_char(last_day(add_months(to_date('01-02-2013','dd-mm-yyyy'),-1)) + 1,
'dd-mm-yyyy') FROM dual;
I'm not entirely sure what you're doing though... if you want the first day of the month that date is in, you can do this:
SELECT to_char(trunc(to_date('01-02-2013', 'dd-mm-yyyy'), 'MM'),
'dd-mm-yyyy') FROM dual;
This uses the TRUNC(date) function to effectively round down to the start of the month.