Oracle to_date format issue - oracle

I have an insert statement, where one of the inserted fields is date. I use to_date function to convert string to date in this way:
to_date('10-MAY-10', 'DD-MON-RR')
It works fine, but I found, that it allows also variants like:
to_date('10?MAY?10', 'DD-MON-RR')
to_date('10+MAY+10', 'DD-MON-RR')
I'm expecting an Oracle error, however it makes an insert. Could you please explain why or give a reference to relevant documentation?

Oracle will test for other formats if it fails to find a match in the string - you can see the rules for what it looks for here in the documentation.
As an aside, years have four digits. Please make sure you specify all four when you provide a date-as-a-string, where possible; it saves the database from having to guess and potentially getting it wrong. I.e. your original example should be:
to_date('10-05-2010', 'DD-MM-YYYY')
If you need to restrict the date-as-a-string to a specific format, you can use the fx format modifier, which is mentioned earlier in the same document I linked to previously.
eg. to_date('10/05/2010', 'dd-mm-yyyy') would match but to_date('10/05/2010', 'fxdd-mm-yyyy') would fail

Related

ORA-00926 Missing Values Keyword

Beginner in SQL i'm currently unable to run this insert basic command.
insert into Project(ProjId,MedicName,Purpose,Start_date,End_date,PI_Id)
insert into Project values('PR003','Medic3','lung','01-Nov-14','31-DEC-20','10101');
ERROR at line 2:
ORA-00926: missing VALUES keyword
Your syntax is wrong. You need to write one statement:
insert into Project(ProjId,MedicName,Purpose,Start_date,End_date,PI_Id)
values('PR003','Medic3','lung','01-Nov-14','31-DEC-20','10101');
Apart from the wrong syntax (you've already been told that), as it appears that certain columns in that table are DATE datatype, I'd suggest you not to enter strings into it, but dates. Becuase, both '01-Nov-14' and '31-DEC-20' are strings.
Don't rely on Oracle's implicit conversion. As long as it might work now, it'll fail sooner or later (when NLS settings change) not necessarily on this database, but on some other. For example, your values wouldn't fit into my database because my format is different, as well as language (we don't use English names). Take control over it.
You could
use date literal (which I used for start_date)
use TO_DATE function with appropriate format mask (end_date below)
Something like this:
INSERT INTO project (projid,
medicname,
purpose,
start_date,
end_date,
pi_id)
VALUES ('PR003',
'Medic3',
'lung',
DATE '2014-11-01', --> this
TO_DATE('31.12.2020', 'dd.mm.yyyy'), --> this
'10101');

Oracle: Why does to_date() accept 2 digit year when I have 4 digits in format string? - and how to enforce 4 digits?

I want to check a date for correctness. (Let's not talk about the fact, that the date is stored in a varchar please ...)
Dates are stored like DDMMYYYY so for instance 24031950 is a correct date. 240319 is not.
So I do this, when the call works, it's a correct date:
select to_date('24031950','DDMMYYYY') from dual;
But unfortunately this also does not return an error:
select to_date('240319','DDMMYYYY') from dual (why?);
But it's interesting, that this one does not work:
select to_date('190324','YYYYMMDD') from dual;
So, how to enforce a check o 4 digit year with the given format mask?
Thanks!
Quoting the docs:
Oracle Database converts strings to dates with some flexibility. [...]
And I believe that flexibility is what you are seeing. You can turn it off with the fx modifier:
FX: Requires exact matching between the character data and the format model
select to_date('240319','fxDDMMYYYY') from dual;
Gives an ORA-01862 error.
Just an additional note to Mat's answer. fx acts like a switch in the string.
For example TO_DATE('2019-11-5','fxYYYY-MM-DD') gives an ORA-01862 error because exact matching applies for the entire string. If you need exact match only for parts of the string, then use for example
TO_DATE('2019-11-5','fxYYYY-MM-fxDD')
In this case YYYY-MM- has to match exactly, whereas DD applies flexible (or lazy) match.
To check whether it is in correct format without exceptions you can also use regex functions.
One possible way would to be check if the string contains 8 digits:
select REGEXP_INSTR ('24031950', '[0-9]{8}') from dual;
1
select REGEXP_INSTR ('240350', '[0-9]{8}') from dual;
0

Oracle a non-numeric character was found where a numeric was expected

I have problem with some thing input multiple date through prompt
my query something like
select something
from
something
where
to_date (bus.TDATE) not in (:didb1)
I want to input like '12-Jun-2016','11-Jun-2016'
i am doing php oracle,
My code following:
select bus.*,con.* from
BusinessPayment bus,
ConsumerPayment con
where bus.TDATE=con.TDATE
and to_date (bus.TDATE) not in (:didbv)
');
$bscode1='11-June-2016','10-June-2016','09-June-2016';
oci_bind_by_name($stid, ':didbv', $bscode1);
oci_execute($stid);
You can't use a single bind variable to represent a list of values in an in() clause. Bind variables don't contain multiple values; the value you bind is seen as a single string value. So you're effectively doing:
where
to_date (bus.TDATE) not in (q'['11-June-2016','10-June-2016','09-June-2016']')
If TDATE is already a date type - which it hopefully is, and the joins suggest it might be - then you should not be passing that through to_date() - you are doing an implicit conversion from date to string, then a semi-explicit conversion back to a date, both using your session's NLS_DATE_FORMAT. That is either doing unnecessary work, or losing resolution, depending on your format model and whether the dates have times. If the intention is to ignore the time part of the value then there are better ways to do that.
Anyway, since that is a date now whatever type it was before, the right had side of that filter will also be converted to a date, so you're doing:
where
to_date (bus.TDATE) not in (to_date(q'['11-June-2016','10-June-2016','09-June-2016']'))
... and it's that which is throwing the exception, whatever your NLS settings are. Even if you passed a single value it would error because of the embedded single quotes. You can replicate that with:
select to_date(q'['11-June-2016','10-June-2016','09-June-2016']') from dual;
which also gets ORA-01858: a non-numeric character was found where a numeric was expected.
Ideally you would pass the individual date strings as elements of an array, but you can also work around this with an XML hack. You can pass a single string containing comma-delimited values to XMLTable(), and it will split it in to rows:
select * from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']');
COLUMN_VALUE
--------------------------------------------------------------------------------
11-June-2016
10-June-2016
09-June-2016
Then you can convert each of those values to a date:
select to_date(column_value, 'DD-Month-YYYY')
from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']')
and use that in a subquery or a join:
select * from dual
where trunc(sysdate) not in (select to_date(column_value, 'DD-Month-YYYY')
from xmltable(q'['11-June-2016','10-June-2016','09-June-2016']'));
And that works with a string bind variable, so your code would be:
select bus.*,con.*
from BusinessPayment bus
join ConsumerPayment con
on bus.TDATE=con.TDATE
where bus.TDATE not in (select to_date(column_value, 'DD-Month-YYYY')
from xmltable(:didbv));
I've modified this to use ANSI join syntax, which isn't relevant but there's rarely a reason to use the ancient syntax you have. If TDATE does include the time you'll need to modify it a bit - truncating is simplest but might affect performance.
Or you could join:
select bus.*,con.*
from xmltable(:didbv) x
join BusinessPayment bus
on bus.TDATE >= to_date(x.column_value, 'DD-Month-YYYY')
and bus.TDATE < to_date(x.column_value, 'DD-Month-YYYY') + 1
join ConsumerPayment con
on bus.TDATE=con.TDATE
In this version TDATE can have a time, and it matches any time on the days specified in the bind variable.
It would be better to supply the dates in a format that doesn't have the month name in it, as that could give you problems when run in different sessions or locales. If you know the PHP side will always be English you could force that to be recognised:
on bus.TDATE >= to_date(x.column_value, 'DD-Month-YYYY', #NLS_DATE_LANGUAGE=ENGLISH')
but if you can change the PHP format to use month numbers, and change the Oracle format model to match, that would be a bit simpler.

Oracle TO_DATE function

I always thought that to_date function string and date format should match. Why is the below statement working fine?
select TO_DATE('20151014','yyyy-mm-dd') from dual;
Is oracle now ignoring the special characters before converting string to date?
This is in Oracle 11g.
I found this interesting and asked the Google, which told me that basically when formats don't match Oracle tries it's hardest to make it work:
https://asktom.oracle.com/pls/apex/f?p=100:11:::NO:RP:P11_QUESTION_ID:9522299800346947976
http://www.oracledba.co.uk/tips/dates_8i.htm
You can use the 'FX' format string to make it match exactly:
http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements004.htm#r18c1-t65
http://docs.oracle.com/cd/E11882_01/server.112/e41084/sql_elements004.htm#SQLRF00216
You learn something new every day! Thanks for asking this!

using oracle to_date function without a format mask

this may be a dumb question however.. I have these two selects: 1st one returns a result, while 2nd gives me a not a valid month error. I can't seem to figure out why..
select to_date('09-12-14','dd-mm-rr') - to_date('01/january/2007') from dual;
select to_date('09-12-14','dd-mm-rr') - to_date('01-01-2007') from dual;
Tnx in advance
When you don't specify a format mask, Oracle will use the NLS_DATE_FORMAT setting (and some predefined masks) to determine the date time format mask.
Apparently your server settings support the first format, and not the second. Therefore it is better to always specify your format mask.

Resources