Substraction with decimal in ORACLE SQL - sql

I need to substract 2 timestamps in the given format:
16/01/17 07:01:06,165000000
16/01/17 07:01:06,244000000
I want to express the result with 2 decimal values but somewhere in the CAST process I am loosing precision. My atempt by now goes this way:
select
id,
trunc((CAST(MAX(T.TIMESTAMP) AS DATE) - CAST(MIN(T.TIMESTAMP) AS DATE))*24*60*60,2) as result
from table T
group by id;
But I get id_1 '0' as a result for the two timestamps above even after I set the truncate decimals at 2.
Is there a way that I can obtain the 0.XX aa a result of the substraction?

It's because you are casting the timestamp to date.
Use to_timestamp to convert your string into timestamp.
Try this:
with your_table(tstamp) as (
select '16/01/17 07:01:06,165000000' from dual union all
select '16/01/17 07:01:06,244000000' from dual
),
your_table_casted as (
select to_timestamp(tstamp,'dd/mm/yy hh24:mi:ss,ff') tstamp from your_table
)
select trunc(sysdate + (max(tstamp) - min(tstamp)) * 86400 - sysdate, 2) diff
from your_table_casted;
The difference between two timestamps is INTERVAL DAY TO SECOND.
To convert it into seconds, use the above trick.

DATE—This datatype stores a date and a time, resolved to the second. It does not include the time zone. DATE is the oldest and most commonly used datatype for working with dates in Oracle applications.
TIMESTAMP—Time stamps are similar to dates, but with these two key distinctions: you can store and manipulate times resolved to the nearest billionth of a second (9 decimal places of precision), and you can associate a time zone with a time stamp, and Oracle Database will take that time zone into account when manipulating the time stamp.
The result of a substraction of two timestamps is an INTERVAL:
INTERVAL—Whereas DATE and TIMESTAMP record a specific point in time, INTERVAL records and computes a time duration. You can specify an interval in terms of years and months, or days and seconds.
You can find more information here

Related

Interval Date to days [duplicate]

I have two timestamp columns: arrTime and depTime.
I need to find the number of munites the bus is late.
I tried the following:
SELECT RouteDate, round((arrTime-depTime)*1440,2) time_difference
FROM ...
I get the following error: inconsistent datatype . expected number but got interval day to second
How can i parse the nuber of minutes?
If i simply subtract: SELECT RouteDate, arrTime-depTime)*1440 time_difference
The result is correct but not well formatted:
time_difference
+00000000 00:01:00 0000000
The result of timestamp arithmetic is an INTERVAL datatype. You have an INTERVAL DAY TO SECOND there...
If you want the number of minutes one way would be to use EXTRACT(), for instance:
select extract( minute from interval_difference )
+ extract( hour from interval_difference ) * 60
+ extract( day from interval_difference ) * 60 * 24
from ( select systimestamp - (systimestamp - 1) as interval_difference
from dual )
Alternatively you can use a trick with dates:
select sysdate + (interval_difference * 1440) - sysdate
from (select systimestamp - (systimestamp - 1) as interval_difference
from dual )
The "trick" version works because of the operator order of precedence and the differences between date and timestamp arithmetic.
Initially the operation looks like this:
date + ( interval * number ) - date
As mentioned in the documentation:
Oracle evaluates expressions inside parentheses before evaluating those outside.
So, the first operation performed it to multiply the interval by 1,440. An interval, i.e. a discrete period of time, multiplied by a number is another discrete period of time, see the documentation on datetime and interval arithmetic. So, the result of this operation is an interval, leaving us with:
date + interval - date
The plus operator takes precedence over the minus here. The reason for this could be that an interval minus a date is an invalid operation, but the documentation also implies that this is the case (doesn't come out and say it). So, the first operation performed is date + interval. A date plus an interval is a date. Leaving just
date - date
As per the documentation, this results in an integer representing the number of days. However, you multiplied the original interval by 1,440, so this now represented 1,440 times the amount of days it otherwise would have. You're then left with the number of seconds.
It's worth noting that:
When interval calculations return a datetime value, the result must be an actual datetime value or the database returns an error. For example, the next two statements return errors:
The "trick" method will fail, rarely but it will still fail. As ever it's best to do it properly.
SELECT (arrTime - depTime) * 1440 time_difference
FROM Schedule
WHERE ...
That will get you the time difference in minutes. Of course, you can do any rounding that you might need to to get whole minutes....
Casting to DATE first returns the difference as a number, at least with the version of Oracle I tried.
round((cast(arrTime as date) - cast(depTime as date))*1440)
You could use TO_CHAR then convert back to a number. I have never tested the performance compared to EXTRACT, but the statement works with two dates instead of an interval which fit my needs.
Seconds:
(to_char(arrTime,'J')-to_char(depTime,'J'))*86400+(to_char(arrTime,'SSSSS')-to_char(depTime,'SSSSS'))
Minutes:
round((to_char(arrTime,'J')-to_char(depTime,'J'))*1440+(to_char(arrTime,'SSSSS')-to_char(depTime,'SSSSS'))/60)
J is julian day and SSSSS is seconds in day. Together they give an absolute time in seconds.

How to subtract hours and minutes from each other in PostgreSQL

I have two fields dateTS and closingTime.
dateTS is a normal timestamp field (e.g. 2019-07-13 22:31:10.000000)
closingTime is a HH:MM format of when a store closes (e.g. 23:00)
I need a PostgreSQL query to subtract the two field and get the number of minutes difference between them.
Using the examples given above the difference between the two fields would be 28 minutes
So far I've tried different variations of the datediff function, but it won't work.
My guess is I either have to
a. generate a fake timestamp for closingTime which is the same day as the dateTs field and subtract the 2 timestamps.
or
b. convert the hour/minutes of both field to a float and subtract the two values to get the hours difference and convert that to minutes
You can just subtract them by converting the timestamp to a time:
select closingtime - datets::time
from your_table;
That will give you an interval as the result.
To convert that to minutes you can get the number of seconds and divide it by 60:
select (extract epoch from closingtime - datets::time) / 60
from your_table;
Cast your closing time to an interval and the timestamp to time and then subtract the two. By casting the timestamp to time you are effectively discarding the date part. You can the subtract one from the other to generate the difference as an interval.
select closingTime::interval - dateTS::time...
e.g.:
# select '23:00'::interval - now()::time;
?column?
-----------------
05:31:00.031141
(1 row)
If needed you can then convert the interval to minutes:
# select extract(epoch from ('23:00'::interval - now()::time)) / 60;
?column?
------------------
327.435313083333
(1 row)

Oracle 11g and SQL Server EPOCH-3600 and EPOCH (Unix_timestamp)

I need to write a select query that gets data in between EPOCH(datetime)-3600 AND EPOCH(datetime).
select all incidents modified in specific date range between EPOCH(datetime)-3600 AND EPOCH(datetime)
So my query is:
SELECT *
FROM TABLENAME
WHERE COLUMN_NAME BETWEEN COLUMNNAME-3600 AND COLUMNNAME
Will this query get the data from 1 hour ago to the current time, in Unix TimeStamp format?
Given a column (COLUMN_NAME) where data is stored as a unix timestamp (eg number of seconds elapsed since January 1st, 1970), you are looking to filter records based on a DATE passed as parameter.
My understanding is that you need a way to convert a unix timestamp to a date. There is no such built-in function in Oracle, however you are allowed to add a number to a date, where the number represents the number of days to add.
Try :
SELECT *
FROM TABLENAME
WHERE
TO_DATE('01/01/1970', 'dd/mm/yyyy') + COLUMN_NAME/60/60/24 -- convert unix timestamp to date
BETWEEN :mydate - 3600 AND :mydate
;
Replace both :mydate with the actual DATE for which you want the search to be performed.

NUMTODSINTERVAL in Redshift. Convert a number to hours

My goal is to offset timestamps in table Date_times to reflect local timezones. I have a Timezone_lookup table that I use for that, which has a column utc_convert and its values are (2, -1, 5, etc.) depending on the timezone.
I used to use NUMTODSINTERVAL in Oracle to be able to convert the utc_convert values to hours so I can add/subtract from the datetimes in the Date_times table.
For Redshift I found INTERVAL, but that's only hardcoding the offset with a specific number.
I also tried:
SELECT CAST(utc as TIME)
FROM(
SELECT *
,to_char(cast(utc_convert as int)||':00:00', 'HH24') as utc
from Timezon_lookup
)
But this doesn't work as some number in the utc_convert column have negative values. Any ideas?
Have you tried multiplying the offset by an interval:
select current_timestamp + utc_convert * interval '1 hour'
In Oracle, you can use the time zone of the user's session (which means you do not need to maintain a table of time zone look-ups or compensate for daylight savings time).
SELECT FROM_TZ( your_timestamp_column, 'UTC' ) AT LOCAL
FROM Date_times
SQLFIDDLE
In RedShift you should be able to use the CONVERT_TIMEZONE( ['source_timezone',] 'target_timezone', 'timestamp') function rather adding a number of intervals. This would allow you to specify the target_timezone as a numeric offset from UTC or as a time zone name (which would automatically compensate for DST).

Compare date + time with timestamp

I have a table with two temporal columns. First (name is DATE) is storing the date (not including the time part) and therefor the datatype is DATE. Second column (name is TIME) is for storing the time in seconds and therefor the datatype is NUMBER.
I need to compare this two dates with a timestamp from another table. How can I calculate the date of the two columns (DATE and TIME) and compare to the timestamp of the other table?
I have tried to calculate the hours out of the time column and add it to the date column, but the output seems not correct:
SELECT to_date(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
The output is just the date, but not the time component.
You can use the INTERVAL DAY TO SECOND type:
SELECT your_date + NUMTODSINTERVAL(your_time_in_seconds, 'SECOND') FROM dual;
Example:
SELECT TRUNC(SYSDATE) + NUMTODSINTERVAL(39687, 'SECOND') FROM dual;
The calculated date with time is: 10-11-2013 11:01:27
This is a better idea than dividing your value by 3600 in my opinion, as you have an interval in seconds, so it feels natural to use an interval to represent your time, which can then be easily added to a column of DATE datatype.
Oracle Interval in Documentation
NUMTODSINTERVAL Function in documentation
date + (time/3600) is already a DATE, so you don't need to do to_date(). It does have the time part you added though, you just aren't displaying it. If you want to output that as a string in the format you've shown, use to_char() instead:
SELECT to_char(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
... except that if time is actually in seconds, you need to divide by 86400 (24x60x60), not 3600. At the moment you're relying on your client's default date format, probably NLS_DATE_FORMAT, which doesn't include the time portion from what you've said. That doesn't mean the time isn't there, it just isn't displayed.
But that is just for display. Leave it as a date, by just adding the two values, when comparing against you timestamp, e.g.
WHERE date + (time/86400) < systimestamp
Try like this,
SELECT TO_DATE('11/11/2013','dd/mm/yyyy') + 3600/60/60/24 FROM DUAL;
Your query,
SELECT date + time/60/60/24 FROM mytable;
try using to_timestamp instead of to_date