Oracle : Date time subtraction - sql

I have to calculate time difference in minutes from current(sysdate) and modified time:-
to_date(to_char(sysdate, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS')
- to_date(to_char(modified, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS')
but problem is to_char returns proper time:-
to_char(whenmodified, 'YYYY-MM-DD HH24:MI:SS')
Outputs 2016-05-23 14:55:50
and to_date doesn’t show time:-
to_date(to_char(modified, 'YYYY-MM-DD HH24:MI:SS'), 'YYYY-MM-DD HH24:MI:SS')
Outputs: 2016-05-23
Please assist how I can get time difference by converting to_char to to_date.
NOTE:
I cant do sysdate-modified because both sysdate and modified gives date without time e.g 2016-05-23
Using to_char for sysdate or modified give date with time 2016-05-23 14:55:50
As we cant subtracts dates in to_char function I am again converting back them to to_date for getting time.
I am expecting:
2016-05-23 14:55:50 - 2016-05-23 14:53:50 = 2 min

I have to calculate time difference in minutes from current(sysdate) and modified time
Oracle Setup:
CREATE TABLE table_name ( modified DATE );
INSERT INTO table_name
SELECT TIMESTAMP '2016-05-23 14:20:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2016-05-23 00:00:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2016-05-01 00:00:00' FROM DUAL UNION ALL
SELECT TIMESTAMP '2016-01-01 00:00:00' FROM DUAL;
Query:
SELECT ( sysdate - modified ) * 24 * 60 AS minute_difference
FROM table_name;
Output:
MINUTE_DIFFERENCE
-----------------
3.66666667
863.666667
32543.6667
206783.667
And to address your comment that:
to_date doesn’t show time
A date always has a time component and never has a format internally to the database (it is represented by 7 or 8 bytes) - the formatting of a date is done by the client program that you use to access the database (and often the default is not to show the time component - however, the time component still exists).
You can change this either in the preferences of your client program or, if they don't use that to control it, by changing the NLS_DATE_FORMAT session parameter:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

Related

ORACLE using TO_DATE to check if item is within last hour

I have a query that I am trying to use TO_DATE to check if ERROR_DT is a data that is within one hour of the current time
Here is what I have so far
SELECT BERROR_DT FROM SomeTable
WHERE ERROR_DT>=TO_CHAR(TO_DATE( SYSDATE, 'MM/DD/YYYY HH12:MI:SS AM') -1, 'fmMM/DDfm/YYYY HH12:MI:SS AM');
Error_DT has a value of (e.g.) 5/18/2020 6:45:15 PM
When I run this I get
ORA-01830: date format picture ends before converting entire input string
I followed the said link and it still is not working. How would I fix this so that I can still remove all 0s in front of the month and the date?
I would suggest converting the date string to the corresponding date value, then do the comparison:
select berror_dt
from sometable
where to_date(error_dt, 'fmMM/DD/YYYY HH12:MI:SS AM') >= sysdate - interval '1' hour
Bottom line, you should fix your data model and store dates as a date-like datatype rather than as a string. The above predicate is not efficient, because the conversion needs to be executed for each and every value of error_dt before the filtering applies, hence defeating an existing index on the column.
Obviously wrong thing you're doing is applying TO_DATE to SYSDATE which is a function that returns DATE datatype.
What you could do is to subtract sysdate and error_dt (I presume its datatype is DATE as well) and see whether difference is less than 1 hour. As difference of two dates is number of days, you have to divide it by 24 (as there are 24 hours in a day).
Something like this:
SQL> alter session set nls_date_format = ' dd.mm.yyyy hh:mi:ss am';
Session altered.
SQL> with test (id, error_dt) as
2 (select 1, to_date('18.05.2020 10:30:15 PM', 'dd.mm.yyyy hh:mi:ss am') from dual
3 union all
4 select 2, to_date('18.05.2020 05:20:55 AM', 'dd.mm.yyyy hh:mi:ss am') from dual)
5 select t.id, t.error_dt, sysdate
6 from test t
7 where sysdate - t.error_dt < 1 / 24;
ID ERROR_DT SYSDATE
---------- ----------------------- -----------------------
1 18.05.2020 10:30:15 PM 18.05.2020 11:02:24 PM
SQL>
If ERROR_DT is a DATE value you just need to use something like
SELECT BERROR_DT
FROM SomeTable
WHERE ERROR_DT >= SYSDATE - INTERVAL '1' HOUR
or if you prefer to use old-fashioned pre-INTERVAL calculations
SELECT BERROR_DT
FROM SomeTable
WHERE ERROR_DT >= SYSDATE - (1/24)

How to add hours to date in 24 hours format

I would like to add, for example, 8 hours to the enddate in a 24 hour format.
I tried adding + 8/24, 'DD-MM-YYYY HH24:MI:SS' on the first line but this gives an error.
This is my query thus far.
SELECT to_char(IN_ENDDATE, 'DD-MM-YYYY HH24:MI:SS')
INTO IN_END_DATE_STRING
FROM DUAL;
Your first line converts a date to a string. You cannot then add 8/24 to it. Do the addition before the conversion:
SELECT to_char(IN_ENDDATE + 8/24.0, 'DD-MM-YYYY HH24:MI:SS')
INTO IN_END_DATE_STRING
FROM DUAL;
IN_ENDDATE really does need to be a date type to allow +8/24 to work. If it's a timestamp, add it as an interval:
IN_ENDDATE + INTERVAL '8' HOUR
This form might be safer to use for a couple of reasons:
it works on both date and timestamps
it's more readable
If IN_ENDDATE is a non-date type (eg varchar) then your query works without the +8/24 because it is being successfully implicitly converted from varchar to date, before being passed to to_char. In this case either be explicit about your conversion:
SELECT to_char(to_date(IN_ENDDATE, 'YYMMDD WHATEVER') + 8/24.0, 'DD-MM-YYYY HH24:MI:SS')
INTO IN_END_DATE_STRING
FROM DUAL
SELECT to_char(to_date(IN_ENDDATE, 'YYMMDD WHATEVER') + INTERVAL '8' HOUR, 'DD-MM-YYYY HH24:MI:SS')
INTO IN_END_DATE_STRING
FROM DUAL
Or set your IN_ENDDATE parameter to really be a date type

CAST(CURRENT_TIMESTAMP AS TIME)

i am trying to work with timestamps and manipulate the data out of them so i can measure different things in our database.
currently i have a column that holds a "DATE" but in fact contains a whole stamp 'DD/MM/YYYY HH24:MI:SS'
i want to be able to grab all entries where "DTIME" between "09:00" and "09:15" however have not been able to cast it correctly.
If i was to output the column without any conversion it would look like this
SELECT ia.DTIME3
FROM ISIS_AUDIT ia
WHERE ia.DTIME3 like to_date('24/01/2019', 'DD/MM/YYYY');
OUTPUT: 24/JAN/19
if i was to convert it to_char,
SELECT to_char(ia.DTIME3, 'DD/MM/YYYY HH24:MI:SS')
FROM ISIS_AUDIT ia
WHERE ia.DTIME3 like to_date('24/01/2019', 'DD/MM/YYYY');
OUTPUT: 24/01/2019 07:10:52
I want to be able to take this DTIME3 and find entries between the times but CAST and CONVERT to TIME doesnt work.
This is my working option but it outputs the date still and i dont want to have to specify the date so it can be run across any day of the week.
WHERE ia.DTIME3 between to_date('24/01/2019 09:00:00', 'DD/MM/YYYY HH24:MI:SS') and to_date('24/01/2019 09:15:00', 'DD/MM/YYYY HH24:MI:SS');
OUTPUT: 24/01/2019 09:00:01
currently i have a column that holds a "DATE" but in fact contains a whole stamp 'DD/MM/YYYY HH24:MI:SS'
That's what Oracle DATE datatype does : storing a date and time (without fractional seconds, that belong to the TIMESTAMP datatypes). There is no specific format in Oracle for date only (without time).
To filter on the time of the day, you can use the TO_CHAR() function to convert your date to a string that represents its time, and that you can compare :
TO_CHAR(ia.DTIME3, 'hh24:mi') BETWEEN '09:00' AND '09:14'
You can also CAST the date to a timestamp and use the EXTRACT() function :
EXTRACT(HOUR FROM CAST(ia.DTIME3 AS TIMESTAMP)) = 9
AND EXTRACT(MINUTE FROM CAST(ia.DTIME3 AS TIMESTAMP)) < 15
Oracle has DATE and TIMESTAMP data types; both have year, month, day, hour, minute, second components (TIMESTAMP also has fractional seconds). Oracle does not have a TIME data type.
Instead, use TRUNC() to truncate the time component to midnight and add an interval literal:
SELECT *
FROM ISIS_AUDIT
WHERE DTIME BETWEEN TRUNC( DTIME ) + INTERVAL '09:00' HOUR TO MINUTE
AND TRUNC( DTIME ) + INTERVAL '09:15' HOUR TO MINUTE;
and ia.DTIME1 not between to_date('&&S_DATE 08:50:00', 'DD/MM/YYYY HH24:MI:SS') and to_date('&&S_DATE 09:20:00', 'DD/MM/YYYY HH24:MI:SS')
and ia.DTIME1 not between to_date('&&S_DATE 11:50:00', 'DD/MM/YYYY HH24:MI:SS') and to_date('&&S_DATE 12:40:00', 'DD/MM/YYYY HH24:MI:SS')
and ia.DTIME3 not between to_date('&&S_DATE 08:50:00', 'DD/MM/YYYY HH24:MI:SS') and to_date('&&S_DATE 09:20:00', 'DD/MM/YYYY HH24:MI:SS')
and ia.DTIME3 not between to_date('&&S_DATE 11:50:00', 'DD/MM/YYYY HH24:MI:SS') and to_date('&&S_DATE 12:40:00', 'DD/MM/YYYY HH24:MI:SS')
i was trying to do this way however i noticed if i have a start time of 08:30 and a finish time of 09:30 then it falls between 09:00 and 09:15 so i want to exclude it from the table. the current WHERE clause im using is quite specific and will only exclude if the timestamp contains the values specified.
Really it would want to read "DTIME1 to DTIME3 not between 09:00 and 09:15"

date range in oracle apps report

The following sql when run with these parameters,
:P_COMP_DATE_FROM = '15-NOV-2015'
:P_COMP_DATE_TO = '15-NOV-2015'
compares as between '15-NOV-2015 00:00:00' and '15-NOV-2015 00:00:00'
Select Ordered_date
From xxcost_rep
Where DATE_COMPLETED BETWEEN NVL(fnd_date.canonical_to_date(:P_COMP_DATE_FROM), DATE_COMPLETED) AND NVL(fnd_date.canonical_to_date(:P_COMP_DATE_TO)), DATE_COMPLETED);
how can I compare this as start of the day and end of the day, so can display the correct result in the range.
I am trying the following to add 86399 seconds to make it the end of the day, but receiving error:
WHERE DATE_COMPLETED BETWEEN NVL(fnd_date.canonical_to_date(:P_COMP_DATE_FROM), DATE_COMPLETED) AND NVL(fnd_date.canonical_to_date(to_date(:P_COMP_DATE_TO,'DD-MON-YYYY')+interval '86399' second), DATE_COMPLETED)
{P_TO_CUSTOMER=, P_COMP_DATE_FROM=2015/11/15 00:00:00, P_COMP_DATE_TO=2015/11/15 00:00:00, P_TO_ORDER_NUMBER=, P_CUST_REGION=, P_TO_DATE=, P_JOB_STATUS=, P_FROM_DATE=, P_FROM_ORDER_NUMBER=, P_FROM_CUSTOMER=}
Calling XDO Data Engine...
--SQLException
java.sql.SQLDataException: ORA-01861: literal does not match format string
ORA-01861: literal does not match format string
The above error is because the date literal doesn't match with the format mask.
For example,
SQL> SELECT TO_DATE('2015118','yyyy/mm/dd') FROM dual;
SELECT TO_DATE('2015118','yyyy/mm/dd') FROM dual
*
ERROR at line 1:
ORA-01861: literal does not match format string
You might be storing dates as string, and there might be strings with different date formats. Therefore, your function fnd_date.canonical_to_date might be failing for such date literals while converting into DATE using TO_DATE.
Also, you should not depend on your client's NLS date format. Remember, TO_DATE is NLS dependent. You should explicitly mention the format mask.
For example,
SQL> SELECT to_date('11/18/2015 00:00:00', 'mm/dd/yyyy hh24:mi:ss') date_from,
2 to_date('11/18/2015 23:59:59', 'mm/dd/yyyy hh24:mi:ss') date_to
3 FROM dual;
DATE_FROM DATE_TO
------------------- -------------------
11/18/2015 00:00:00 11/18/2015 23:59:59
In your case, you need to compare the dates. You could do it like the below example,
SQL> WITH DATA AS(
2 SELECT DATE '2015-11-18' dt FROM dual
3 )
4 SELECT * FROM DATA
5 WHERE dt
6 BETWEEN to_date(
7 to_char(dt, 'mm/dd/yyyy')||' 00:00:00',
8 'mm/dd/yyyy hh24:mi:ss'
9 )
10 AND to_date(
11 to_char(dt, 'mm/dd/yyyy')||' 23:59:59',
12 'mm/dd/yyyy hh24:mi:ss'
13 );
DT
-------------------
11/18/2015 00:00:00
UPDATE
For the first part where you just need the start time, you don't have to add the time portion as 00:00:00since DATE has both date and time elements. When you do not mention the time portion, it defaults to midnight i.e. 00:00:00.
For example, add INTERVAL '86399' SECOND:
SQL> SELECT DATE '2015-11-18' from_date,
2 DATE '2015-11-18' + INTERVAL '86399' SECOND to_date
3 FROM dual;
FROM_DATE TO_DATE
------------------- -------------------
11/18/2015 00:00:00 11/18/2015 23:59:59

Oracle DB select between dates

I would like to query number of records between night 12.01 AM to 11.59 PM but issue is, I would like to schedule this query so I cant specify any hard coded dates.
Query should pull number of records for query date between 12.01 AM to 11.59 PM.
Could someone please help me on this.
Query should pull number of records for query date between 12.01 AM to 11.59 PM.
You could do it as:
TRUNC gives you date element truncating the time portion
convert the SYSDATE into string using TO_CHAR
then concatenate the time element
finally convert everything back to DATE
SYSDATE returns the current date and time set for the operating system on which the database resides. The datatype of the returned value is DATE, and the format returned depends on the value of the NLS_DATE_FORMAT initialization parameter.
So, you don't have to hard-code any DATE value if you want to execute the query everyday.
Use the following in the filter predicate:
BETWEEN
TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY') ||' 00:01', 'MM/DD/YYYY HH24:MI')
AND
TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY') ||' 23:59', 'MM/DD/YYYY HH24:MI')
Demo
SQL> alter session set nls_date_format = 'MM/DD/YYYY HH24:MI:SS';
Session altered.
SQL> SELECT to_date(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
2 ||' 00:01', 'MM/DD/YYYY HH24:MI') start_dt ,
3 to_date(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
4 ||' 23:59', 'MM/DD/YYYY HH24:MI') end_date
5 FROM dual;
START_DT END_DATE
------------------- -------------------
05/06/2015 00:01:00 05/06/2015 23:59:00
SQL>
So, you don't have to put any hard-coded value for current date, the SYSDATE will take care of it. All you are doing is:
TRUNC gives the date element by truncating the time portion.
Then concatenating the required time element
Converting the entire string into DATE using TO_DATE
I would like to schedule this query so I cant specify any hardcord dates
To schedule the query to execute everyday, you could use DBMS_SCHEDULER.
I'm going to assume you want everything that happens during the date of interest. So you want everything from and including midnight of that day and before midnight of the next day.
declare
AsOf Date = date '2015-01-01 13:14:15';
select ...
from tablename
where tabledate >= trunc( AsOf )
and tabledate < trunc( AsOf ) + 1;
If you know the date doesn't have a time portion, just can eliminate the calls to trunc. But you may want to keep them just in case.