ORA-01843 not a valid month- Comparing Dates - sql

I have a problem when try to select data from a table filtering by date.
For example:
SELECT * FROM MYTABLE WHERE MYTABLE.DATEIN = '23/04/49';
The Oracle Error is:
Informe de error:
Error SQL: ORA-01843: mes no válido
01843. 00000 - "not a valid month"
*Cause:
*Action:
Probably the source data of table is corrupted, in this case:
How can i solve this problem?
Can I change this dates for null?
The results of this select, select * from nls_session_parameters; , is:
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE SPANISH
NLS_TERRITORY SPAIN
NLS_CURRENCY ¿
NLS_ISO_CURRENCY SPAIN
NLS_NUMERIC_CHARACTERS ,.
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD/MM/RR
NLS_DATE_LANGUAGE SPANISH
NLS_SORT SPANISH
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT DD/MM/RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT DD/MM/RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY ¿
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE

You should use the to_date function (oracle/functions/to_date.php
)
SELECT * FROM MYTABLE WHERE MYTABLE.DATEIN = TO_DATE('23/04/49', 'DD/MM/YY');

You are comparing a date column to a string literal. In such a case, Oracle attempts to convert your literal to a date, using the default date format.
It's a bad practice to rely on such a behavior, as this default may change if the DBA changes some configuration, Oracle breaks something in a future revision, etc.
Instead, you should always explicitly convert your literal to a date and state the format you're using:
SELECT * FROM MYTABLE WHERE MYTABLE.DATEIN = TO_DATE('23/04/49','MM/DD/YY');

If you don't need to check exact timestamp, use
SELECT * FROM MYTABLE WHERE trunc(DATEIN) = TO_DATE('23-04-49','DD-MM-YY');
otherwise, you can use
SELECT * FROM MYTABLE WHERE DATEIN = TO_DATE('23-04-49 20:18:07','DD-MM-YY HH24:MI:SS');
Here, you use hard code date,if you directly compare then you must use DD-MM-YY HH24:MI:SS else you might get ORA-01849: hour must be between 1 and 12.

I know this is a bit late, but I'm having a similar issue. SQL*Plus executes the query successfully, but Oracle SQL Developer shows the ORA-01843: not a valid month error.
SQL*Plus seems to know that the date I'm using is in the valid format, whereas Oracle SQL Developer needs to be told explicitly what format my date is in.
SQL*Plus statement:
select count(*) from some_table where DATE_TIME_CREATED < '09-12-23';
VS
Oracle SQL Developer statement:
select count(*) from some_table where DATE_TIME_CREATED < TO_DATE('09-12-23','RR-MM-DD');

Just in case this helps, I solved this by checking the server date format:
SELECT * FROM nls_session_parameters WHERE parameter = 'NLS_DATE_FORMAT';
then by using the following comparison (the left field is a date+time):
AND EV_DTTM >= ('01-DEC-16')
I was trying this with TO_DATE but kept getting an error. But when I matched my string with the NLS_DATE_FORMAT and removed TO_DATE, it worked...

In a comment to one of the answers you mention that to_date with a format doesn't help. In another comment you explain that the table is accessed via DBLINK.
So obviously the other system contains an invalid date that Oracle cannot accept. Fix this in the other dbms (or whatever you dblink to) and your query will work.
Having said this, I agree with the others: always use to_date with a format to convert a string literal to a date. Also never use only two digits for a year. For example '23/04/49' means 2049 in your system (format RR), but it confuses the reader (as you see from the answers suggesting a format with YY).

If the source date contains minutes and seconds part, your date comparison will fail.
you need to convert source date to the required format using to_char and the target date also.

If you are using command line tools, then you can also set it in the shell.
On linux, with a sh type shell, you can do for example:
export NLS_TIMESTAMP_FORMAT='DD/MON/RR HH24:MI:SSXFF'
Then you can use the command line tools and it will use the specified format:
/path/to/dbhome_1/bin/sqlldr user/pass#host:port/service control=table.ctl direct=true

Try using:
SELECT *
FROM MYTABLE
WHERE MYTABLE.DATEIN is not null
AND MYTABLE.DATEIN = '23/04/49';

Use the month as a string.
Example:
(12-Apr-2002) or (12-April-2002)

Although the answers using TO_DATE are correct, I prefer to use the ANSI SQL format for dates:
DATEIN = DATE '1949-04-23'
It works in Oracle and other DBMS ANSI SQL compliant. This is specially important if your application is DBMS agnostic.

Try alter session set NLS_DATE_FORMAT='DD/MM/YY'; -- or whatever format you want
I faced the same problem, on PROD, all the code were already in this format, but on preprod, it's not set,
So this means you change the default date format used by oracle

ALTER session set NLS_LANGUAGE=’AMERICAN’;

Related

How do you convert YYYY_MM to date in Oracle SQL?

I have a column which has dates as texts. Like: '2021_01' (I will reefer this column as TextDate)
I convert it to '2021-01' with this code:
SELECT REPLACE(at.TextDate,'_','-') as DataFormat FROM tableName at
But when I try to cast it to date, or convert it to date, I always get 'Missing expression' errors. I tried this:
SELECT REPLACE(CONVERT(VARCHAR(7), at.TextDate, 126, '_', '-') as date FROM tableName at
But it will give me errors. Any suggestion?
convert means something completely different in Oracle than it does elsewhere. You need the to_date() function:
SELECT TO_DATE(at.textDate, 'YYYY_MM') as DataFormat FROM tableName at
If you want to display it in a particular format then you can either let your client/application do that - most clients by default will use your session's NLS_DATE_FORMAT setting - or explicitly convert it back to a string with the complementary to_char() function.
db<>fiddle
The valid date elements are also in the documentation. You should only convert to a string for display though; while you are manipulating or storing it you should treat it as a date.
How can I filter last 3 months with it?
You need to use Oracle syntax, not SQL Server or other syntax. You also can't refer to a column alias in the same level of query. SO you can recalculate the date value; or as your string format is relatively sane you can convert the target date to a string and compare that, which might allow an index to be used. Something like:
SELECT TO_DATE(at.textDate, 'YYYY_MM') as DataFormat
FROM tableName at
WHERE at.textDate >= TO_CHAR(ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -3), 'YYYY_MM')
db<>fiddle
TO_DATE with appropriate format mask.
Just to know what's what:
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
Code:
SQL> select to_date('2021-01', 'yyyy_mm') from dual;
TO_DATE('2021-01','
-------------------
01.01.2021 00:00:00
SQL>

How to insert date in SQL date type column?

I have a table with date type column.
I am trying to insert date in it:
But I get an error:
Please give me to make the correct query to put the date
Easy fix::
INSERT INTO t(dob) VALUES(DATE '2015-12-17');
Assuming this is an Oracle question based on the ORA-01843 error message, the problem appears to be in the date formatting as the error suggests.
In the provided example does the date '6-3-2012' mean '3 March 2012' or 'June 6, 2012?' The answer lies within the NLS_DATE_FORMAT parameter.
Out of the box, the Oracle date format is DD-MON-RR. So your corrected date format is either '03-MAR-12' or '06-JUN-12.' If the NLS_DATE_FORMAT has not been changed.
Never try to insert a string into a date column! If you have a string, use the to_date function with an explicit date format (and use 4 digit dates).
Relying on nls_date_format to implicitly convert your strings is just asking for trouble (like you just did), it can very easily change, even some apps will change it themselves.
The date literal (date '2015-12-17' https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements003.htm#BABGIGCJ) always uses the same date format so that might be okay for ad hoc statements but you need to be aware that it is literal by name and literal by nature. They don't support bind variables so you will end up writing unshareable SQL to chew up your shared pool.

I have an oracle table which has date in dd-mm-yyyy and dd/mm/yyyy format in same field. Now i have to convert into one common format

I have an oracle table which has date in dd-mm-yyyy and dd/mm/yyyy format in same field. Now i have to convert into one common format.
Please suggest how to approach this?
I did tried but it is failing as it is failing due to invalid month.
Is there a way i can first identify what format the date is and then based on case statement i might convert.
or something easy way? Please
I trust you've learnt your lesson and you're now going to store these dates in the date data type.
Your two different date formats actually aren't important, Oracle already is a little over accepting when it comes to separating characters.
e.g
to_date('01/01/1900','dd-mm-yyyy')
Does not error
I did tried but it is failing as it is failing due to invalid month.
Your error is coming because you've allowed a value that doesn't match either of those formats into your string column.
If you are on version 12.2 at least (which you should be in 2020) then you can use the validate_conversion function to identify rows that don't convert to a date with your format (https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqlrf/VALIDATE_CONVERSION.html#GUID-DC485EEB-CB6D-42EF-97AA-4487884CB2CD)
select string_column
from my_table
where validate_conversion(string_column AS DATE,'dd/mm/yyyy') = 0
The other additional helper we got in 12.2 was the on conversion error clause of to_date. So you can do.
alter table my_table add my_date date;
update my_table set my_date = to_date(my_string default null on conversion error,'dd/mm/yyyy');
If you are confident that there is no other format than those two, a simple approach is replace():
update mytable set mystring = replace(mystring, '/', '-');
This turns all dates to format dd-mm-yyyy.
I would suggest taking a step forward and convert these strings to a date column.
alter table mytable add mydate date;
update mytable set mydate = to_date(replace(mystring, '/', '-'), 'dd-mm-yyyy');
This will fail if invalid date strings are met. I tend to consider that a good thing, since it clearly signals that this a problem with the data. If you want to avoid that, you can use on conversion error, available starting Oracle 12:
to_date(
replace(mystring, '/', '-') default null on conversion error,
'dd-mm-yyyy'
)
Then you can remove the string column, which is no longer needed.

Issue querying date from oracle.

I understand that querying a date will fail as its comparing a string to date and that can cause an issue.
Oracle 11.2 G
Unicode DB
NLS_DATE_FORMAT DD-MON-RR
select * from table where Q_date='16-Mar-09';
It can be solved by
select * from table where trunc(Q_date) = TO_DATE('16-MAR-09', 'DD-MON-YY');
What I don't get is why this works.
select* from table where Q_date='07-JAN-08';
If anyone can please elaborate or correct my mindset.
Thanks
Oracle does allow date literals, but they depend on the installation (particularly the value of NLS_DATE_FORMAT as explained here). Hence, there is not a universal format for interpreting a single string as a date (unless you use the DATE keyword).
The default format is DD-MM-YY, which seems to be the format for your server. So, your statement:
where Q_date = '07-JAN-08'
is interpreted using this format.
I prefer to use the DATE keyword with the ISO standard YYYY-MM-DD format:
where Q_Date = DATE '2008-01-07'
If this gets no rows returned:
select * from table where Q_date='16-Mar-09';
but this does see data:
select * from table where trunc(Q_date) = TO_DATE('16-MAR-09', 'DD-MON-YY');
then you have rows which have a time other than midnight. At this point in the century DD-MON-RR and DD-MON-YY are equivalent, and both will see 09 as 2009, so the date part is right. But the first will only find rows where the time is midnight, while the second is stripping the time off via the trunc, meaning the dates on both sides are at midnight, and therefore equal.
And since this also finds data:
select* from table where Q_date='07-JAN-08';
... then you have rows at midnight on that date. You might also have rows with other times, so checking the count with the trunc version might be useful.
You can check the times you actually have with:
select to_char(q_date, 'YYYY-MM-DD HH24:MI:SS') from table;
If you do want to make sure you catch all times within the day you can use a range:
select * from table where
q_date >= date '2009-03-16'
and q_date < date '2009-03-17';
Quick SQL Fiddle demo.
Although it sounds like you're expecting all the times to be midnight, which might indicate a data problem.

Oracle to_date() incorrect output

There must be a very simple answer, but I can't find it anywhere.
I have the following which is a section of my select statement:
case when q.renewal_date is not null then
to_date(q._renewal_date, 'DD/MM/YYYY')
else
to_date(w.END_DATE, 'DD/MM/YYYY')
end END_DATE,
according to all of the docs I can find the MM should give the month in numbers however I'm getting results such as:
30-SEP-12
26-JUN-11
30-SEP-12
It's also interesting that they're hyphenated (-) and not with slashes (/).
So what's the reason for this and how do I achieve what I want?
Assuming w.end_Date and q._renewal_date are actual dates, you want to to_char them, not to_date. At present I would say you are seeing the dates in the format specified by your NLS settings. (If they are not dates, you are converting them to dates, but still letting your NLS settings choose the format you view it in)
As you are TO_DATEing the value it is stored by Oracle internally as a date. It is displayed back to you using your NLS_DATE settings value which i would assume are set to DD-MON-YY by default.
You can check with
SELECT *
FROM v$parameter
WHERE name = 'nls_date_format';
You'll need to either alter your NLS_DATE_FORMAT setting (either for your session or for the DB) or TO_CHAR the output to the format you want to see.
to_date converts a string to a date. The code you have is taking a string (q._renewal_date) in 'DD/MM/YYYY' format and converting it to a date. What you are seeing is the default rendering of the date field.
Depending on what type q._renewal_date is, you probably need to use a different conversion/formatting function.