Difference in dates in Oracle - sql

I am writing the following query
SELECT
TO_CHAR(TO_DATE(data_elaborazione, 'YYYYMMDD') -
TO_DATE(DATA_INS_AGG_SDS, 'YYYYMMDD') )AS DateDiff
FROM
dual
I want to calculate the difference between the two dates, in days, but I get an error:
ORA-00904: "DATA_INS_AGG_SDS": invalid identifier
The same goes for data_elaborazione too. Data_elaborazione, DATA_INS_AGG_SDS are both varchar types that contain dates as varchar

The error you are getting is cause by you referencing columns on dual that do not exist. You'll need to select these columns from the tables they actually exist in. As for your date arithmetic, it should return a number, which does not require TO_CHAR to display, unless you have some specific formatting concerns. Here is an example of date arithmetic. The second date value has a time component. So, the two columns due the date arithmetic and display the result, the second essentially rounds down to just get the number of days to an even integer value.
Please read the comments about data types. You should always work with values in their correct data types. Avoid storing either dates or numbers as strings in the DB.
-- start test_data
with some_data(begin_date, end_date) as
(select to_date('02/15/2017','MM/DD/YYYY'), to_date('04/03/2017 09:34:12','MM/DD/YYYY HH24:MI:SS') from dual)
-- end test data
select end_date - begin_date as num_days_diff_w_time,
FLOOR(end_date - begin_date) as num_days_diff_wo_time
from some_data;

Related

SQL Oracle table blank when trying to query date data stored as varchar

I have a column called received_dt_key in Varchar in the format DD-MM-YYYY (e.g. 30-07-2021).
I would like to select all from the table for dates between 31-12-2021 and 01-01-2022. I have tried version of the below query and a blank table is the output.
SELECT *
FROM SD_BDAY
WHERE to_char(to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY')) > to_char(to_date('31-12-2021', 'DD-MM-YYYY'))
and to_char(to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY')) < to_char(to_date('01-01-2022', 'DD-MM-YYYY'));
Don't compare dates as strings. Compare them as dates:
SELECT *
FROM SD_BDAY
WHERE to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') > to_date('31-12-2021', 'DD-MM-YYYY')
and to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') < to_date('01-01-2022', 'DD-MM-YYYY');
If you try to compare them as strings then you are looking for string that is greater than '31-12-2021' and less than '01-01-2022' and the string comparison will look at the first character and see if it can find a match which is greater than '3' and less than '0'; there can never be such a match so it is quite correct that when comparing as strings nothing is returned.
As pointed out by #AlexPoole in comments, even if you compare the values as dates (rather than strings) you will still never return a result as finding values that are greater than DATE '2021-12-31' and less than DATE '2022-01-01' would return all dates from 2021-12-31 00:00:01 to 2021-12-31 23:59:59; however, your values will always be converted with a midnight time component and, therefore, will never fall into that range so cannot be returned.
What you probably want is to use >= rather than > and then it would match values on 2021-12-31.
The best thing would be to store calendar dates in date data type column. Why else do you think Oracle designed that data type? This way you may create normal indexes on data data type columns, or, if needed, partition the table by that date column.
Still, if you insist in having the calendar dates stored like that, I think the below should work:
SELECT *
FROM SD_BDAY
WHERE to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') >
to_date('31-12-2021', 'DD-MM-YYYY')
and to_date(RECEIVED_DT_KEY, 'DD-MM-YYYY') <
to_date('01-01-2022', 'DD-MM-YYYY');
Thus you compare calandar dates with calendar dates, not varchar with varchar, as it results from the code you have written.
And what if in the varchar2 column there is somethibng that can't be converted to date? That is why it is best to use the date data type.

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.

Date difference = 0 in where clause Oracle?

I have the same problem as this. The only difference is that I use Oracle. I want to select the rows which has insertion_date='20.11.2018'. So my query was
select * from table where insertion_date='20.11.2018'
In that question they suggested datediff, so I looked at its equivalent in oracle and I learned that I can do date arithmetic. So I tried somethings like these:
select * from table where insertion_date -'20.11.2018'=0;
It gave ora-00932 inconsistent datatypes expected date got number.
So, then I tried;
select * from table where insertion_date - to_date('20.11.2018', 'dd.MM.YYYY') = 0;
It does not give error but also does not display the results which I know there must be. What am I doing wrong here? Thanks.
Update: Sorry I forgot to mention that insertion_date is type date. But it also has time(hour, minutes, seconds) info in it.
What is INSERTION_DATE's datatype?
If it is DATE, then comparing it to another date (note: this is date literal; value you used is a string!)
select * from table where insertion_date = date '2018-11-20'
might work, unless INSERTION_DATE contains time component (hours and minutes). Then, the simplest option is to truncate its value (so that you get date itself, at midnight):
select * from table where trunc(insertion_date) = date '2018-11-20'
but it'll ruin index you have on that column (unless it is a function-based one). For small tables, it won't make any difference. For large amount of data, it would so convert it to
select * from table where insertion_date >= date '2018-11-20'
and insertion_date < date '2018-11-21'
If, on the other hand, INSERTION_DATE is a string (VARCHAR2 or CHAR) datatype (which is a really bad idea; consider switching to DATE datatype), then you have to know its format, convert it to DATE first and then compare to another date. For example, if it was a string that contains date values in format dd.mm.yyyy, then
select * from table where to_date(insertion_date, 'dd.mm.yyyy') = date '2018-11-20'
This will certainly fail if any string in that column doesn't match such a format or contains invalid values (such as "date" 53.67.Bx48).

Oracle SQL - convert a varchar2 into a date

I have a problem with converting a varchar2 fields into a date format.
I got 2 columns with the datatyp varchar2, one is called qtime the other is called ztime. Both fields contain strings in this format (f.e. 152015 -> would be a timestamp 15:20:15).
For reporting reasons I need to convert this fields into a date format, afterwards I want to substract (qtime-ztime) the fields an convert them into the format [hh] (f.e. after the operation 01:20:00 would be -> 01). Is it possible to to this within Oracle SQL 12c? The biggest problem for me right now is that I don't get those Strings converted into a date format.
select TO_DATE(qtime,'MM/DD/YYYY hh24:mi:ss') just gives me
ORA-01861:"literal does not match format string"
select TO_DATE(qtime,'hh24mmss') gives me a wrong Date
01.03.2018
select TO_TIMESTAMP(qtime,'hh24mmss') gives me a wrong Date
01.03.2018 BUT the correct time with f.e. 15:20:15,0000000
Thank you in advance, any help is appreciated
Note: I only have reading rights on the database Oracle 12c, so I need to to this within Statements
"The Database contains another column with the correct date for each time"
The missing piece of the puzzle! Concatenate the two columns to get something which can be converted to an Oracle DATE:
select to_date(qdate||qtime, 'yyyymmddhh24miss') as qdatetime
, to_date(zdate||ztime, 'yyyymmddhh24miss') as zdatetime
from your_table
Once you have done that you can perform arithmetic of the dates e.g.
select id
, zdatetime - qdatetime as time_diff
from ( select id
, to_date(qdate||qtime, 'yyyymmddhh24miss') as qdatetime
, to_date(zdate||ztime, 'yyyymmddhh24miss') as zdatetime
from your_table
)
If you want the number of hours in the difference you can include this expression in the projection of the outer query:
, extract( hour from (zdatetime - qdatetime) day to second) as hrs_ela
First off, if you are trying to convert a varchar2 into a date without specifying neither day nor month, it will default to the first day of the current month:
If you specify a date value without a date, then the default date is the first day of the current month.
You can read up more here
Also in 2nd and 3rd your example, you are using 'hh24mmss' for specifying hour, minute and second components, but do note that correct format for minutes is 'mi' and not 'mm', which is used for months.
So the solution is to concatenate both date and time component when creating the date as the other answer suggested, tho I would recommend using a single date field as it can store the information you need.

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);