Teradata timestamp subtraction with difference in minutes - sql

select StartDatetime,EndDatetime,
(TRIM((COALESCE(CAST((CAST(EndDatetime AS TIME) - CAST(StartDatetime AS TIME) MINUTE(4)) AS INT),'')))) as TimeDiff
From Table1
EndDatetime and StartDatetime are columns of type Timestamp(6). The above query gave the difference in between the timestamps in minutes. It is working if both the timestamps are present in the same day. But when EndDatetime is having a value of tomorrow wrt to the StartDatetime then the TimeDiff value that is being returned is a negative value. Using absolute function is not a best solution because then the TimeDiff number itself isn't accurate.
How to get the timestamp difference precisely in minutes?

here is one way by using extract :
Select
StartDatetime,EndDatetime
,(CAST((CAST(EndDatetime AS DATE)- CAST(StartDatetime AS DATE)) AS DECIMAL(18,6)) * 60*24)
+ ((EXTRACT(HOUR FROM EndDatetime) - EXTRACT(HOUR FROM StartDatetime))* 60)
+ ((EXTRACT(MINUTE FROM EndDatetime) - EXTRACT(MINUTE FROM StartDatetime)))
+ ((EXTRACT(SECOND FROM EndDatetime) - EXTRACT(SECOND FROM StartDatetime))/60)
AS "Difference in Minutes"
from Table1

Related

How to calculate average time when it is used TIME format in Bigquery?

I'm trying to get the AVG time, but the time format is not supported by the AVG function. I tried with CAST function, like in some posts were explained, but it seems doesn't work anyway. Thanks
WITH october_fall AS
(SELECT
start_station_name,
end_station_name,
start_station_id,
end_station_id,
EXTRACT (DATE FROM started_at) AS start_date,
EXTRACT(DAYOFWEEK FROM started_at) AS start_week_date,
EXTRACT (TIME FROM started_at) AS start_time,
EXTRACT (DATE FROM ended_at) AS end_date,
EXTRACT(DAYOFWEEK FROM ended_at) AS end_week_date,
EXTRACT (TIME FROM ended_at) AS end_time,
DATETIME_DIFF (ended_at,started_at, MINUTE) AS total_lenght,
member_casual
FROM
`ciclystic.cyclistic_seasonal_analysis.fall_202010` AS fall_analysis
ORDER BY
started_at DESC)
SELECT
COUNT (start_week_date) AS avg_start_1,
AVG (start_time) AS avg_start_time_1, ## here is where the problem start
member_casual
FROM
october_fall
WHERE
start_week_date = 1
GROUP BY
member_casual
Try below
SELECT
COUNT (start_week_date) AS avg_start_1,
TIME(
EXTRACT(hour FROM AVG(start_time - '0:0:0')),
EXTRACT(minute FROM AVG(start_time - '0:0:0')),
EXTRACT(second FROM AVG(start_time - '0:0:0'))
) as avg_start_time_1
member_casual
FROM
october_fall
WHERE
start_week_date = 1
GROUP BY
member_casual
Another option would be
SELECT
COUNT (start_week_date) AS avg_start_1,
PARSE_TIME('0-0 0 %H:%M:%E*S', '' || AVG(start_time - '0:0:0')) as avg_start_time_1
member_casual
FROM
october_fall
WHERE
start_week_date = 1
GROUP BY
member_casual
Because BigQuery cannot calc AVG on TIME type, you would see the error message if you tried to do so.
Instead you could calc AVG by INT64.
The time_ts is timestamp format.
I tried to use time_diff to calc the differences from time to "00:00:00", then I could get the seconds in FLOAT64 format and cast it to INT64 format.
I create a function secondToTime. It's pretty straightforward to calc hour / minute / second and parse back to time format.
For the date format, I think you could do it in the same way.
create temp function secondToTime (seconds INT64)
returns time
as (
PARSE_TIME (
"%H:%M:%S",
concat(
cast(seconds / 3600 as int),
":",
cast(mod(seconds, 3600) / 60 as int),
":",
mod(seconds, 60)
)
)
);
with october_fall as (
select
extract (date from time_ts) as start_date,
extract (time from time_ts) as start_time
from `bigquery-public-data.hacker_news.comments`
limit 10
) SELECT
avg(time_diff(start_time, time '00:00:00', second)),
secondToTime(
cast(avg(time_diff(start_time, time '00:00:00', second)) as INT64)
),
secondToTime(0),
secondToTime(60),
secondToTime(3601),
secondToTime(7265)
FROM october_fall
I know a few months have passed, but maybe someone else will be facing the same issue.
As for the section where the problem occurred, something like this worked for me and gave the average ride_length:
FORMAT_TIMESTAMP
('%T',
TIMESTAMP_SECONDS(CAST(AVG(TIME_DIFF(ride_length, '00:00:00', SECOND)) AS
INT64)))
AS avg_ride_length

How to search for records with timestamp between two given time in Postgresql

Is there a way to search through timestamp data in a database and select only data with timestamps between 8AM and 6PM?
Example timestamp format is 2021-06-14 14:01:26.839629, I want to do a search and only return results where time is after 8AM and before 6PM.
You can use (as per https://www.postgresql.org/docs/current/functions-datetime.html):
SELECT EXTRACT(HOUR FROM TIMESTAMP '2001-02-16 20:38:40');
This will return the hour from the timestamp and you can also filter accordingly.
I would recommend:
where col::time >= '06:00:00' and col::time < '18:00:00'
select *
from MyTable
where CAST(Created as time) >= '08:00'
or CAST(Created as time) < '18:00'
Try this.

BigQuery: extract SECOND from TIMESTAMP

How can i run this query?
Error Message: No matching signature for function EXTRACT for argument types: DATE_TIME_PART FROM INT64. Supported signatures: EXTRACT(DATE_TIME_PART FROM DATE); EXTRACT(DATE_TIME_PART FROM TIMESTAMP [AT TIME ZONE STRING]); EXTRACT(DATE_TIME_PART FROM DATETIME); EXTRACT(DATE_TIME_PART FROM TIME) at [12:12]
They both give the same error message
WHERE EXTRACT( SECOND FROM event_timestamp )
- EXTRACT( SECOND FROM last_event) >= (60 * 10)
OR last_event IS NULL
WHERE EXTRACT( SECOND FROM event_timestamp AT TIME ZONE "UTC")
- EXTRACT( SECOND FROM last_event AT TIME ZONE "UTC") >= (60 * 10)
OR last_event IS NULL
use TIMESTAMP_MICROS()
WHERE EXTRACT( SECOND FROM TIMESTAMP_MICROS(event_timestamp))
- EXTRACT( SECOND FROM last_event) >= (60 * 10)
OR last_event IS NULL
If you want events that are more than 10 minutes from the previous timestamp, just use some arithmetic and comparisons:
where event_timestamp > last_event + (60 * 10 * 1000000) or
last_event is null
You are storing the timestamp as a microseconds value. You don't need to convert to another type.
If you really wanted to convert this to timestamp values, you could use:
where timestamp_micros(event_timestamp) > timestamp_add(timestamp_micros(last_event), interval 10 minute) or
last_event is null
In particular, you don't want to extract seconds. That value is always going to be between 0 and 59.

Select Data From Multiple Days Between Certain Times (Spanning 2 days)

I need to know how many entries appear in my DB for the past 7 days with a timestamp between 23:00 & 01:00...
The Issue I have is the timestamp goes across 2 days and unsure if this is even possible in the one query.
So far I have come up with the below:
select trunc(timestamp) as DTE, extract(hour from timestamp) as HR, count(COLUMN) as Total
from TABLE
where trunc(timestamp) >= '12-NOV-19' and
extract(hour from timestamp) in ('23','00','01')
group by trunc(timestamp), extract(hour from timestamp)
order by 1,2 desc;
The result I am hoping for is something like this:
DTE | Total
20-NOV-19 5
19-NOV-19 4
18-NOV-19 4
17-NOV-19 6
Many thanks
Filter on the day first comparing it to TRUNC( SYSDATE ) - INTERVAL '7' DAY and then consider the hours by comparing the timestamp to itself truncated back to midnight with an offset of a number of hours.
select trunc(timestamp) as DTE,
extract(hour from timestamp) as HR,
count(COLUMN) as Total
from TABLE
WHERE timestamp >= TRUNC( SYSDATE ) - INTERVAL '7' DAY
AND ( timestamp <= TRUNC( timestamp ) + INTERVAL '01:00' HOUR TO MINUTE
OR timestamp >= TRUNC( timestamp ) + INTERVAL '23:00' HOUR TO MINUTE
)
group by trunc(timestamp), extract(hour from timestamp)
order by DTE, HR desc;
Subtract or add an hour to derive the date. I'm not sure what date you want to assign to each period, but the idea is:
select trunc(timestamp - interval '1' hour) as DTE,
count(*) as Total
from t
where trunc(timestamp - interval '1' hour) >= DATE '2019-11-12' and
extract(hour from timestamp) in (23, 0)
group by trunc(timestamp - interval '1' hour)
order by 1 desc;
Note: If you want times between 11:00 p.m. and 1:00 a.m., then you want the hour to be 23 or 0.

Calculate Average Time Over 24 hour period

I'm working in Teradata and am trying to calulate the average time a job completes.
Data Values:
Job Name Start Date End Date End Time
D_BDW_CCIP_SRM_LD 10/10/2012 10/11/2012 01:41:49
D_BDW_CCIP_SRM_LD 10/9/2012 10/10/2012 00:19:56
D_BDW_CCIP_SRM_LD 10/8/2012 10/8/2012 23:37:18
D_BDW_CCIP_SRM_LD 10/5/2012 10/5/2012 23:39:47
D_BDW_CCIP_SRM_LD 10/4/2012 10/4/2012 23:42:47
D_BDW_CCIP_SRM_LD 10/3/2012 10/3/2012 23:41:54
The average is coming back with 16:07 instead of 00:07. What I need to happen is that the calculations where the job finishes next day understands that the time expanded.
In Excel I could do this by adding one day to the end time and then averaging and displaying as a time.
How do I do this in Teradata?
This is such an interesting question! UPDATED with correct syntax: Assuming your START_DATE and END_DATE are DATE values and END_TIME is a TIME value, here is a solution:
select cast( avg( case
when start_date <> end_date
then extract(second from end_time)
+ extract(minute from end_time) * 60
+ extract(hour from end_time) * 3600
+ 86400
else extract(second from end_time)
+ extract(minute from end_time) * 60
+ extract(hour from end_time) * 3600
end) mod 86400) as decimal(10,4))
* INTERVAL '00:00:01.00' HOUR TO SECOND as avg_time
from your_table
The CASE expression "adds" one day (86,400 seconds) as you suggested when using Excel to determine the average seconds since midnight into an intermediate result and converted into a TIME column.
To be fair, I received help from the Teradata Forum formatting the result, but I like this so much I'll be using it myself.
This seems to do the trick, but I'd be interested in seeing if there is another way.
SELECT job_name,
case when avg_end_time_in_minutes > 60*24 then avg_end_time_in_minutes - 60*24
else avg_end_time_in_minutes end as avg_adjusted,
case when max_end_time_in_minutes > 60*24 then max_end_time_in_minutes - 60*24
else max_end_time_in_minutes end as max_adjusted,
CAST((CAST(avg_adjusted / 60 AS INTEGER) (FORMAT '9(2)')) AS CHAR(2))||':'||
CAST((CAST((avg_adjusted / 60 MOD 1)*60 AS INTEGER) (FORMAT '9(2)')) AS CHAR(2))
avg_adjusted_time,
CAST((CAST(max_adjusted / 60 AS INTEGER) (FORMAT '9(2)')) AS CHAR(2))||':'||
CAST((CAST((max_adjusted / 60 MOD 1)*60 AS INTEGER) (FORMAT '9(2)')) AS CHAR(2))
max_adjusted_time
FROM (
SELECT job_name,
AVG(end_time_in_minutes) avg_end_time_in_minutes,
MAX(CAST(end_time_in_minutes AS DECIMAL(8,2))) max_end_time_in_minutes
FROM (
SELECT job_name,
CAST(substr(end_time, 1, 2) AS INTEGER)*60
+ CAST(substr(end_time, 4, 2) AS INTEGER)
+ cast(end_date - start_date as integer)*60*24 AS end_time_in_minutes
FROM dabank_prod_ops_tb.bdw_tables_load_tracker_view a
WHERE a.status = 'COMPLETED'
AND a.start_date BETWEEN CURRENT_DATE - 31 AND CURRENT_DATE -1
AND a.end_time IS NOT NULL
) a
GROUP BY 1
) b
First, figure out the number of seconds that the end time is from midnight on the start date. We can then use that to calculate the average number of seconds taken, and then add that to midnight to find the average end time.
select
avg(extract(second from end_time) + 60 *
(extract(minute from end_time) + 60 *
(extract(hour from end_time) + 24 *
(end_date - start_date))) as avg_duration_in_seconds
cast(avg_duration_in_seconds / 60 / 60 as integer) as avg_hours
mod(cast(avg_duration_in_seconds / 60 as integer), 60) as avg_minutes
mod(cast(avg_duration_in_seconds as integer), 60) as avg_seconds,
cast('00:00:00' as time) +
cast(avg_hours as interval hour) +
cast(avg_minutes as interval minute) +
cast(avg_seconds as interval second) as avg_end_time
from my_table
Be aware though that if the average ends up over 24 hours, avg_end_time will be something like 00:01:15 rather than 24:01:15.