Subtracting/Adding to a Where clause timestamp condition - oracle

I'm attempting to speed up a timestamp comparison query by restricting the query to 30 minutes before and after the timestamp in question. This is the format I'm using:
Causedat
-----
11-NOV-15 10.20.58.000000000 AM
11-NOV-15 10.19.41.877000000 AM
10-NOV-15 11.01.40.000000000 AM
10-NOV-15 11.00.50.460000000 AM
05-NOV-15 01.53.30.966000000 PM
05-NOV-15 01.47.31.000000000 PM
What I'm trying to do is write a condition where i'll tell the system only to look for dates in the system that are +-00:30:00.000000000 (thirty minutes) from the Causedat date in the future or past from that time.
I've seen that for example, SYSDATE - SYSTIMESTAMP is a legitimate calculation. Is it possible to do something similar to this like this:
WHERE search.date >= (Causedat = Causedat - '000000000 00:30:00.000000000')
AND search.date <= (Causedat = Causedat + '000000000 00:30:00.000000000')
Please assume the date i'm searching and Causedat are in the same (timestamp) format for this question.
Thank you for any light you may be able to shine on the problem for me.

You can add an interval to a timestamp; you can read about datetime and interval arithmetic. There are conversion functions to go from a variable to an interval, but with known fixed values you can use an interval literal here. You can use the full string you have:
where search_date >= causedat - interval '000000000 00:30:00.000000000' day to second
and search_date <= causedat + interval '000000000 00:30:00.000000000' day to second;
Or just the non-zero part:
where search_date >= causedat - interval '30' minute
and search_date <= causedat + interval '30' minute;
Trivial demo of how these evaluate:
select systimestamp,
systimestamp - interval '000000000 00:30:00.000000000' day to second as minus_30,
systimestamp + interval '000000000 00:30:00.000000000' day to second as plus_30
from dual;
SYSTIMESTAMP MINUS_30 PLUS_30
----------------------------------- ----------------------------------- -----------------------------------
18-NOV-15 11.39.09.597473000 +00:00 18-NOV-15 11.09.09.597473000 +00:00 18-NOV-15 12.09.09.597473000 +00:00
select systimestamp,
systimestamp - interval '30' minute as minus_30,
systimestamp + interval '30' minute as plus_30
from dual;
SYSTIMESTAMP MINUS_30 PLUS_30
----------------------------------- ----------------------------------- -----------------------------------
18-NOV-15 11.39.09.653809000 +00:00 18-NOV-15 11.09.09.653809000 +00:00 18-NOV-15 12.09.09.653809000 +00:00

Direct arithmetic on date time column with required interval value.
WHERE search.date
BETWEEN Causedat - INTERVAL '30' MINUTE
AND Causedat + INTERVAL '30' MINUTE

I just went through the question. I have provided a simple example to illustrate how we can achieve this.
SELECT A.DT
FROM
( SELECT SYSTIMESTAMP - INTERVAL '60' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP - INTERVAL '30' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP + INTERVAL '30' MINUTE AS DT FROM DUAL
UNION
SELECT SYSTIMESTAMP + INTERVAL '60' MINUTE AS DT FROM DUAL
)A
WHERE A.DT BETWEEN (SYSTIMESTAMP - INTERVAL '30' MINUTE) AND (SYSTIMESTAMP + INTERVAL '30' MINUTE);
Let me know if this helps.

Related

Oracle adding randim amount if seconds to a date

I have a date that is always set to midnight i.e. '07312021 00:00:00' how can I use dbms_random.value to add (1 second, 23:59:59) to that date.
SELECT DATE '2021-07-31' + INTERVAL '1' SECOND * FLOOR(DBMS_RANDOM.VALUE(0, 86400))
FROM DUAL;
Or
SELECT DATE '2021-07-31' + NUMTODSINTERVAL(
FLOOR(DBMS_RANDOM.VALUE(0, 86400)),
'SECOND'
)
FROM DUAL;
Or
SELECT DATE '2021-07-31' + DBMS_RANDOM.VALUE
FROM DUAL;
sqlfiddle here

date format picture ends before converting entire input string in Oracle

I have a PD_HEAT_DATA table with HEATID and HEATDEPARTURE_ACT columns. Data type of HEATDEPARTURE column is VARCHAR2 and it holds timestamps in the format 2019-07-28 23:11:11,359.
My requirement is to retrieve the records from PD_HEAT_DATA table between 6 AM of today and 6 AM of next day.
Sample Data:
HeatID HEATDEPARTURE_ACT
0001024002 2019-07-29 00:46:42,115
0001024003 2019-07-29 06:46:42,115
0001024004 2019-07-29 23:46:42,115
0001024003 2019-07-30 00:06:42,115
0001024004 2019-07-30 04:46:42,115
I have tried following code but it is not giving desired result:
select heatid, HEATDEPARTURE_ACT from hd_heat_data where to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') >= trunc(sysdate
-1) + 6/24 and
to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') < trunc(sysdate) + 6/24
I have tried following code but it is not giving desired result:
select heatid, HEATDEPARTURE_ACT from hd_heat_data where to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') >= trunc(sysdate
-1) + 6/24 and
to_date(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS') < trunc(sysdate) + 6/24
You have fractional seconds at the end of your HEATDEPARTURE_ACT strings which you need to trim off prior to converting the string to a date:
select heatid, HEATDEPARTURE_ACT
from hd_heat_data
where TO_DATE(REGEXP_SUBSTR(HEATDEPARTURE_ACT, '[^,]*'),
'YYYY-MM-DD HH24:MI:SS') BETWEEN trunc(sysdate-1) + INTERVAL '6' HOUR
AND trunc(sysdate) + INTERVAL '6' HOUR - INTERVAL '1' SECOND
dbfiddle here
(Note that I altered the dates in the fiddle data so results would be produced)
You need to change your format provided in TO_TIMESTAMP as TO_TIMESTAMP(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS,FF')
SELECT
HEATID,
HEATDEPARTURE_ACT
FROM
HD_HEAT_DATA
WHERE
TO_TIMESTAMP(HEATDEPARTURE_ACT, 'YYYY-MM-DD HH24:MI:SS,FF')
BETWEEN TRUNC(SYSDATE - 1) + INTERVAL '6' HOUR AND TRUNC(SYSDATE) +
INTERVAL '6' HOUR - INTERVAL '1' SECOND
See the demo of reproduction of the issue and resolution, HERE
Cheers!!

oracle convert unix epoch time to date

The context is that there is an existing application in our product which generates and sends the EPOCH number to an existing oracle procedure & vice versa. It works in that procedure using something like this
SELECT UTC_TO_DATE (1463533832) FROM DUAL
SELECT date_to_utc(creation_date) FROM mytable
When I tried these queries it does work for me as well with Oracle 10g server (and oracle sql developer 4.x if that matters).
In the existing procedure the requirement was to save the value as date itself (time component was irrelevant), however in the new requirement I have to convert unix EPOCH value to datetime (at the hours/mins/seconds level, or better in a specific format such as dd-MMM-yyyy hh:mm:ss) in an oracle query. Strangely I am unable to find any documentation around the UTC_TO_DATE and DATE_TO_UTC functions with Google. I have looked around at all different questions on stackoverflow, but most of them are specific to programming languages such as php, java etc.
Bottom line, how to convert EPOCH to that level of time using these functions (or any other functions) in Oracle query? Additionally are those functions I am referring could be custom or specific somewhere, as I don't see any documentation or reference to this.
To convert from milliseconds from epoch (assume epoch is Jan 1st 1970):
select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 / 1000) * 1322629200000
from dual;
11/30/2011 5:00:00 AM
To convert that date back to milliseconds:
select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60 * 1000
from dual;
1322629200000
If its seconds instead of milliseconds, just omit the 1000 part of the equation:
select to_date('19700101', 'YYYYMMDD') + ( 1 / 24 / 60 / 60 ) * 1322629200
from dual;
select (to_date('11/30/2011 05:00:00', 'MM/DD/YYYY HH24:MI:SS') - to_date('19700101', 'YYYYMMDD')) * 24 * 60 * 60
from dual;
Hope that helps.
Another option is to use an interval type:
SELECT TO_TIMESTAMP('1970-01-01 00:00:00.0'
,'YYYY-MM-DD HH24:MI:SS.FF'
) + NUMTODSINTERVAL(1493963084212/1000, 'SECOND')
FROM dual;
It has this advantage that milliseconds won't be cut.
If your epoch time is stored as an integer.....
And you desire the conversion to Oracle date format.
Step 1-->
Add your epoch date (1462086000) to standard 01-jan-1970. 86400 is seconds in a 24 hour period.
*Select TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 from dual*
**output is 5/1/2016 7:00:00 AM**
Step 2--> Convert it to a CHAR . This is needed for formatting before additional functions can be applied.
*Select TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss') from dual*
output is 2016-05-01 07:00:00
Step 3--> Now onto Timestamp conversion
Select to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss') from dual
output is 5/1/2016 7:00:00.000000000 AM
Step 4--> Now need the TimeZone, usage of UTC
Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') from dual
output is 5/1/2016 7:00:00.000000000 AM +00:00
Step 5--> If your timezone need is PST
Select from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') at time zone 'America/Los_Angeles' TZ from dual
output is 5/1/2016 12:00:00.000000000 AM -07:00
Step 6--> Format the PST Timezone timestamp.
Select to_Char(from_tz(to_timestamp(TO_CHAR(TO_DATE('01-jan-1970', 'dd-mon-yyyy') + 1462086000/86400 ,'yyyy-mm-dd hh24:mi:ss'), 'yyyy-mm-dd hh24:mi:ss'),'UTC') at time zone 'America/Los_Angeles' ,'DD-MON-YYYY HH24:MI:SS') TZ from dual
output is 01-MAY-2016 00:00:00
Step 7--> And finally, if your column is date datatype
Add to_DATE to the whole above Select.
Here it is for both UTC/GMT and EST;
GMT select (to_date('1970-01-01 00','yyyy-mm-dd hh24') +
(1519232926891)/1000/60/60/24) from dual;
EST select new_time(to_date('1970-01-01 00','yyyy-mm-dd hh24') +
(1519232926891)/1000/60/60/24, 'GMT', 'EST') from dual;
I thought somebody would be interested in seeing an Oracle function version of this:
CREATE OR REPLACE FUNCTION unix_to_date(unix_sec NUMBER)
RETURN date
IS
ret_date DATE;
BEGIN
ret_date:=TO_DATE('19700101','YYYYMMDD')+( 1/ 24/ 60/ 60)*unix_sec;
RETURN ret_date;
END;
/
I had a bunch of records I needed dates for so I updated my table with:
update bobfirst set entered=unix_to_date(1500000000+a);
where a is a number between 1 and 10,000,000.
A shorter method to convert timestamp to nanoseconds.
SELECT (EXTRACT(DAY FROM (
SYSTIMESTAMP --Replace line with desired timestamp --Maximum value: TIMESTAMP '3871-04-29 10:39:59.999999999 UTC'
- TIMESTAMP '1970-01-01 00:00:00 UTC') * 24 * 60) * 60 + EXTRACT(SECOND FROM
SYSTIMESTAMP --Replace line with desired timestamp
)) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to timestamp.
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS TIMESTAMP FROM dual;
TIMESTAMP
26/08/20 09:33:47,263027000 UTC
As expected, above methods' results are not affected by time zones.
A shorter method to convert interval to nanoseconds.
SELECT (EXTRACT(DAY FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval --Maximum value: INTERVAL '+694444 10:39:59.999999999' DAY(6) TO SECOND(9) or up to 3871 year
) * 24 * 60) * 60 + EXTRACT(SECOND FROM (
INTERVAL '+18500 09:33:47.263027' DAY(5) TO SECOND --Replace line with desired interval
))) * 1000000000 AS NANOS FROM DUAL;
NANOS
1598434427263027000
A method to convert nanoseconds to interval.
SELECT numtodsinterval(
1598434427263027000 --Replace line with desired nanoseconds
/ 1000000000, 'SECOND') AS INTERVAL FROM dual;
INTERVAL
+18500 09:33:47.263027
As expected, millis, micros and nanos are converted and reverted, dispite of SYSTIMESTAMP doesn't have nanosecounds information.
Replace 1000000000 by 1000, for example, if you'd like to work with milliseconds instead of nanoseconds.
I've tried some of posted methods, but almost of them are affected by the time zone or result on data loss after revertion, so I've decided do post the methods that works for me.

Want to run query from specific time of today to last n hours

Hi I want to run a query which extracts data from 7:00 am in the morning to 3:00 pm yesterday.
I run this query in afternoon.
Below query extracts data from time I run the query. I want the data from 7:00 am and backwards.
select *
from NOTES
where creation_date >= sysdate- interval '17:15' hour to minute
I would appreciate any help.
Try this in Oracle:
SELECT *
FROM NOTES
WHERE creation_date BETWEEN to_timestamp(to_char(sysdate) || ' 00:00:00', 'dd-Mon-yy hh24:mi:ss') - interval '9' hour
AND to_timestamp(to_char(sysdate) || ' 00:00:00', 'dd-Mon-yy hh24:mi:ss') + interval '7' hour;
Try this in MySQL:
SELECT *
FROM NOTES
WHERE creation_date >= (concat(current_date(), ' 00:00:00') - interval '09:00' hour)
AND creation_date <= (concat(current_date(), ' 00:00:00') + interval '07:00' hour);
Try this as optimal
For Oracle
SELECT *
FROM NOTES
WHERE creation_date BETWEEN trunc(sysdate) - INTERVAL '9' HOUR
AND trunc(curdate) + INTERVAL '7' HOUR;
For MySQL
SELECT *
FROM NOTES
WHERE creation_date BETWEEN curdate() - INTERVAL 9 HOUR
AND curdate() + INTERVAL 7 HOUR;
If you need detail info - just ask.

How do I a convert a number to an INTERVAL of minutes?

In pseudo-Oracle, I want to do the following:
select systimestamp + to_interval(select NUMERIC_COLUMN from SOME_TABLE where SOME_TABLE_PK = :stuff) from dual;
If the number of minutes were always the same, I could use an interval literal a la interval '360' minute, but I can't find a simple function to convert a number to a MINUTE interval. What am I missing?
You can use the numtodsinterval function which does exactly the conversion you need (number to interval):
SQL> select systimestamp, systimestamp + numtodsinterval(20, 'MINUTE') from dual;
SYSTIMESTAMP SYSTIMESTAMP+NUMTODSINTERVAL(2
------------------------- -------------------------------
2011-08-22 16:12:24.060 2011-08-22 16:32:24.060

Resources