Asking User to input date in sql giving ORA-00932: inconsistent datatypes: expected DATE got NUMBER Error - sql

I am trying to input a date value from the user and then using that value in the query.
select * from TB_MNP_GTY_TRANS_STEPS where CREATE_DATETIME>=&startdate
Now when i run the sql statement in Toad and input 8/1/2012 as date data type i am getting
ORA-00932: inconsistent datatypes: expected DATE got NUMBER
Can someone suggest where i am wrong.Note that CREATE_DATETIME is of Date Type.

You should really specify what date format you are using in your parameter:
SELECT *
FROM TB_MNP_GTY_TRANS_STEPS
where CREATE_DATETIME >= TO_DATE(&startdate, 'DD/MM/YYYY');
Read about date formats here
Currently your session is expecting the date to be in its default NLS_DATE default fomat and obviously the format of the date you're entering is different.
Explicitly specifying date formats prevents this issue from occurring.
Hope it helps...
EDIT:
If you want to pass in the 8th January 2012 then you could specify your variable value as:
08/01/2012
And your select would be:
SELECT *
FROM TB_MNP_GTY_TRANS_STEPS
where CREATE_DATETIME >= TO_DATE(&startdate, 'DD/MM/YYYY');
Depending upon your environment you might need to wrap the variable in single quotes (for TOAD you definiely will) i.e.
SELECT *
FROM TB_MNP_GTY_TRANS_STEPS
where CREATE_DATETIME >= TO_DATE('&startdate', 'DD/MM/YYYY');
The error you are getting is caused by the format of the date string you are entering not matching EXACTLY the format you are specifying (see the leading "0" before the 8 and 1 in the day and month!)

Date casting necessary
select * from TB_MNP_GTY_TRANS_STEPS where CREATE_DATETIME>=to_date(&startdate, 'MM-DD-YYYY')
and while passing parameter you should pass value in quoets as '08-09-1999'

Related

Cast NUMBER to DATE. Error ORA-00932: inconsistent datatypes: expected DATE got NUMBER

I have a column with a datatype number but I want to convert the column into date. I tried using CAST function but it gives error
ORA-00932: inconsistent datatypes: expected DATE got NUMBER.
For example, 20221203 to 2022-12-03.
Any suggestions?
col_date is the column name
select cast(col_date as date)
from school
Try converting int to varchar and then varchar to date
select cast(cast(col_date as varchar(10)) as date)
Use the to_date() function:
select to_date(col_date, 'YYYYMMDD')
from school
That does an implicit conversion from number to string, but you can make it explicit:
select to_date(to_char(col_date), 'YYYYMMDD')
from school
Of course, it would be better to store your values as proper dates. You may have numbers which don't correspond to actual dates, and will need to decide how to handle those if you do.
Oracle's date datatype always has a time component, which will be set to midnight with this conversion. They have no intrinsic human-readable format - your client decides how to display, usually using your session NLS_DATE_FORMAT setting. You can change that with alter session, which will affect the display of all date values.
If you want to display the date as a string with a particularly format then you can reverse the process with the to_char() function:
select to_char(to_date(to_char(col_date), 'YYYYMMDD'), 'YYYY-MM-DD')
from school
If you only want it reformatted as a string, and don't need it as a real date at all, you could just format the number directly:
select to_char(col_date, 'FM0000G00G00', 'nls_numeric_characters='' -''')
from school
db<>fiddle
But either way, only do that for final display - leave it as an actual date (not string) for any processing, joins, storage etc.

Why I get error when using TO_DATE() while converting from VARCHAR to Date data type

I am currently stuck in error which I don't understand clearly.
ORA-01843: not a valid month
01843. 00000 - "not a valid month"
*Cause:
*Action:
So far I check a couple of post here in Stackoverflow but doesn't help me so much.
I have query something like
SELECT * FROM (
SELECT uta.StartDate,uta.EndDate
FROM user_timesheets_absence uta
LEFT JOIN users u
ON u.UserID = uta.UserID
AND uta.Approved = '0'
AND
((
'2020-01-30' >= TO_DATE(uta.StartDate,'YYYY-MM-DD')
AND
'2020-02-06' <= TO_DATE(uta.EndDate,'YYYY-MM-DD')
)
OR
(
'2020-01-30' <= TO_DATE(uta.StartDate,'YYYY-MM-DD')
AND
'2020-01-30' >= TO_DATE(uta.StartDate,'YYYY-MM-DD')
))
--GROUP BY uta.UserAbsenceID
UNION
SELECT ut.DATE_ AS StartDate,
ut.DATE_ AS EndDate
FROM user_timesheets ut
INNER JOIN moments m ON
m.UserTimesheetsID = ut.UserTimesheetsID
WHERE
TO_DATE(ut.DATE_,'YYYY-MM-DD') BETWEEN '2020-01-21' AND '2020-01-30' + SYSTIMESTAMP + 1
AND ut.user_id = 1
) a
Here is the problem which StartDate and EndDate filled are VARCHAR2
I try using 'TO_TIMESTAMP' and try to change format to YYYY/MM/DD but doesn't work.
I have to be honest that I don't have any idea so far what I made wrong here.
Where I made mistake ? What is wrong here ?
UPDATE
As GMB from answer said that using validate_conversion() gives meall invalid date strings
Result
And so far from query above, when I run it I get following error
ORA-01861: literal does not match format string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Some of the strings in your column are invalid dates. Starting version 12.2, it is easy to exhibit them with function validate_conversion() clause of to_date(). The following query gives you all invalid date strings:
select date_
from user_timesheets
where validate_conversion(date_ as date, 'YYYY/MM/DD') = 0
You can then fix your data.
You should consider using the date datatype to store dates, so that integrity is enforced at the time when the data is written.
In the meantime, let me suggest, however, to optimize the filtering logic: the formats of your strings make it possible to use direct filtering (without prior conversion to a date): this is more efficient, since it does not requires converting the entire column before filtering (on says that the predicate is SARGeable). Typically, you would replace something like:
to_date(uta.startdate,'yyyy/mm/dd') <= '2020-01-30'
With:
ut.startdate <= '2020/01/30'
Or if you are filtering agains the current system date:
ut.startdate <= to_char(sysdate, 'YYYY/MM/DD')
Not all startdate and enddate columns have values in YYYY/MM/DD format or - if they do - they are invalid.
For example: values like 2020/A8/43 or ab3f/xy/2i or 2020/15/02 and similar are invalid.
Error says that MM part of those strings isn't in range between 01 and 12.
First you should be storing date values using date, not strings. One possibility is that these actually are dates and you don't need to reconvert them. Without sample data, it is hard to say. But you should put your effort into fixing the data.
Second, date constants in Oracle should look like:
DATE '2020-01-30'
So:
DATE '2020-01-30' >= TO_DATE(uta.StartDate,'YYYY/MM/DD')

How does ORACLE database convert DATE to NUMBER implicitly?

I'm trying to understand this function:
NVL2( NULL, ( SYSDATE - SYSDATE ), DATE '2020-05-24' ))
And its returned value:
NVL2(NULL,(SYSDATE-SYSDATE),DATE '2020-05-24'))
2458994
I'm having trouble understanding where that number, 2458994, comes from, as SYSDATE-SYSDATE is a NUMBER, and you cannot implicity convert a DATE to a NUMBER:
TO_NUMBER(DATE '2020-05-24')
ORA-01722: invalid number
The ORACLE SQL Language Reference NVL2 states:
If expr2 is numeric data, then Oracle Database determines which argument has the highest numeric precedence, implicitly converts the other argument to that data type, and returns that data type.
So my question is, what form of conversion is ORACLE SQL using on the DATE datatype to make it a NUMBER datatype?
It's effectively doing:
to_number(to_char(DATE '2020-05-24','J'))
The 'J' is (from the docs):
Julian day; the number of days since January 1, 4712 BC. Number specified with J must be integers.
If you run that manually it gets the same value you see:
select to_number(to_char(DATE '2020-05-24','J')) from dual;
2458994
It isn't obvious that it should be doing that, but it is. If the second argument is a plain (type-2) number then you get an error:
select NVL2(NULL,42,to_date('2020-05-24','YYYY-MM-DD')) from dual;
ORA-00932: inconsistent datatypes: expected NUMBER got DATE
If you dump the date subtraction result it comes back as a different (internal, undocumented as far as I can see) data type:
select dump(SYSDATE-SYSDATE) from dual;
Typ=14 Len=8: 114,133,37,0,0,0,0,0
That seems to cause the third argument to be converted to that same type; it's almost equivalent to:
select DATE '2020-05-24' - DATE '-4712-01-01' from dual;
2458993
So it looks like it's either doing something similar to that but adjusting it, or doing an internal version of the 'J' conversion, or... something else vaguely similar. It doesn't seem to be documented behaviour.

Oracle - Selecting employees which were hired in the last 20 years

I cannot use months_between, only playing with DATEs is allowed, so I got this:
select * from emp
where ((SYSDATE- hiredate)/(365+1/4-1/100+1/400)) >= ((SYSDATE/(365+1/4-1/100+1/400))-20);
I dont understand why i get error in
(SYSDATE/(365+1/4-1/100+1/400))-20
saying it is an invalid datatype "inconsistent datatypes: expected %s got %s" when
(SYSDATE-hiredate)/(365+1/4-1/100+1/400)
is working properly with no error, WTF?
PS: an example of using (365+1/4-1/100+1/400) is with birth date, for more precision:
((SYSDATE- birth_date)/(365+1/4-1/100+1/400)) >=18
sysdate retuns the current date and time.
In your second test case as below, you are subtracting two dates which returns
numeric value indicating the number of days between the two dates and so calculation (division was made possible).
(SYSDATE-hiredate)/(365+1/4-1/100+1/400)
In your first test case as below, you are directly trying to divide a date type value.
you cannot divide a date datatype in oracle. Instead you can add any value say x (sysdate +x), it means you are adding x days to the date value.
(SYSDATE/(365+1/4-1/100+1/400))-5
In case, you want to convert the sysdate to number you can try like below
select to_number(to_char(sysdate, 'yyyymmddhh24miss')) from dual;
Which will return you DATE+TIME like 20140608165750 for today.
(OR)
select to_number(to_char(sysdate, 'yyyymmdd')) from dual;
Result will be 20140608 (only the DATE part)
According to Oracle on subtracting two Date datatypes you'll get a Number datatype.
From Oracle docs: Reference
So this part of your query
((SYSDATE- birth_date)/(365+1/4-1/100+1/400)) >=18 returns a number, whereas
In this statement (SYSDATE/(365+1/4-1/100+1/400))-5 sysdate is still taken as a date dataype which is why you're getting the error. You can explicitly use to_number to convert sysdate into number.
Edit: Try this ((to_number(to_char(SYSDATE,'DDMMYYYY'))/(365+1/4-1/100+1/400))-5) to convert your sysdate date dataype into number datatype. So, your select query should look like this
select * from emp
where ((SYSDATE- hiredate)/(365+1/4-1/100+1/400)) >= ((to_number(to_char(SYSDATE,'DDMMYYYY'))/(365+1/4-1/100+1/400))-5);

In Oracle, convert number(5,10) to date

When ececute the following SQL syntax in Oracle, always not success, please help.
40284.3878935185 represents '2010-04-16 09:18:34', with microsecond.
an epoch date of 01 January 1900 (like Excel).
create table temp1 (date1 number2(5,10));
insert into temp1(date1) values('40284.3878935185');
select to_date(date1, 'yyyy-mm-dd hh24:mi:ssxff') from temp1
Error report: SQL Error: ORA-01861: literal does not match format
string
01861. 00000 - "literal does not match format string"
*Cause: Literals in the input must be the same length as literals in
the format string (with the exception of leading whitespace). If the
"FX" modifier has been toggled on, the literal must match exactly,
with no extra whitespace.
*Action: Correct the format string to match the literal.
Thanks to Mark Bannister
Now the SQL syntax is:
select to_char(to_date('1899-12-30','yyyy-mm-dd') +
date1,'yyyy-mm-dd hh24:mi:ss') from temp1
but can't fetch the date format like 'yyyy-mm-dd hh24:mi:ss.ff'. Continue look for help.
Using an epoch date of 30 December 1899, try:
select to_date('1899-12-30','yyyy-mm-dd') + date1
Simple date addition doesn't work with timestamps, at least if you need to preserve the fractional seconds. When you do to_timestamp('1899-12-30','yyyy-mm-dd')+ date1 (in a comment on Mark's answer) the TIMESTAMP is implicitly converted to a DATE before the addition, to the overall answer is a DATE, and so doesn't have any fractional seconds; then you use to_char(..., '... .FF') it complains with ORA-01821.
You need to convert the number of days held by your date1 column into an interval. Fortunately Oracle provides a function to do exactly that, NUMTODSINTERVAL:
select to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY') from temp3;
16-APR-10 09.18.33.999998400
You can then display that in your desired format, e.g. (using a CTE to provide your date1 value):
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SSXFF') from temp3;
2010-04-16 09:18:33.999998400
Or to restrict to thousandths of a second:
with temp3 as ( select 40284.3878935185 as date1 from dual)
select to_char(to_timestamp('1899-12-30','YYYY-MM-DD')+
+ numtodsinterval(date1, 'DAY'), 'YYYY-MM-DD HH24:MI:SS.FF3') from temp3;
2010-04-16 09:18:33.999
An epoch of 1899-12-30 sounds odd though, and doesn't correspond to Excel as you stated. It seems more likely that your expected result is wrong and it should be 2010-04-18, so I'd check your assumptions. Andrew also makes some good points, and you should be storing your value in the table in a TIMESTAMP column. If you receive data like this though, you still need something along these lines to convert it for storage at some point.
Don't know the epoch date exactly, but try something like:
select to_date('19700101','YYYYMMDD')+ :secs_since_epoch/86400 from dual;
Or, cast to timestamp like:
select cast(to_date('19700101', 'YYYYMMDD') + :secs_since_epoch/86400 as timestamp with local time zone) from dual;
I hope this doesn't come across too harshly, but you've got to totally rethink your approach here.
You're not keeping data types straight at all. Each line of your example misuses a data type.
TEMP1.DATE1 is not a date or a varchar2, but a NUMBER
you insert not the number 40284.3878935185, but the STRING >> '40284.3878935185' <<
your SELECT TO_DATE(...) uses the NUMBER Temp1.Date1 value, but treats it as a VARCHAR2 using the format block
I'm about 95% certain that you think Oracle transfers this data using simple block data copies. "Since each Oracle date is stored as a number anyway, why not just insert that number into the table?" Well, because when you're defining a column as a NUMBER you're telling Oracle "this is not a date." Oracle therefore does not manage it as a date.
Each of these type conversions is calculated by Oracle based on your current session variables. If you were in France, where the '.' is a thousands separator rather than a radix, the INSERT would completely fail.
All of these conversions with strings are modified by the locale in which Oracle thinks your running. Check dictionary view V$NLS_PARAMETERS.
This gets worse with date/time values. Date/time values can go all over the map - mostly because of time zone. What time zone is your database server in? What time zone does it think you're running from? And if that doesn't spin your head quite enough, check out what happens if you change Oracle's default calendar from Gregorian to Thai Buddha.
I strongly suggest you get rid of the numbers ENTIRELY.
To create date or date time values, use strings with completely invariant and unambiguous formats. Then assign, compare and calculate date values exclusively, e.g.:
GOODFMT constant VARCHAR2 = 'YYYY-MM-DD HH24:MI:SS.FFF ZZZ'
Good_Time DATE = TO_DATE ('2012-02-17 08:07:55.000 EST', GOODFMT);