How to Aggregate timestamp Values to 15 MIns? - sql

I have some values for some particular timestam like
Time Value
18/10/2016 00:00:00 10
18/10/2016 00:05:00 20
18/10/2016 00:10:00 30
18/10/2016 00:15:00 40
18/10/2016 00:20:00 50
18/10/2016 00:25:00 60
18/10/2016 00:30:00 70
I want to aggregate it to 15 Mins data. My aggregation should be like at 18/10/2016 00:15:00 it should take the average of 5mins,10Mins and 15Mins to give 15th Min data.
My output should be like
Time value
18/10/2016 00:15:00 30
18/10/2016 00:30:00 60
Is there any way to get this in oracle?

Here is one method:
select (trunc(time, 'HOUR') + 15 * trunc(extract(minute from time) / 15) / (60 * 24)) as time,
sum(value)
from t
group by (trunc(time, 'HOUR') + 15 * trunc(extract(minute from time) / 15) / (60 * 24));

Related

(bigquery) how number of hours event is happening within multiple dates

So my data looks like this:
DATE TEMPERATURE
2012-01-13 23:15:00 UTC 0
2012-01-14 01:35:00 UTC 5
2012-01-14 02:15:00 UTC 6
2012-01-14 03:15:00 UTC 8
2012-01-14 04:15:00 UTC 0
2012-01-14 04:55:00 UTC 0
2012-01-14 05:15:00 UTC -2
2012-01-14 05:35:00 UTC 0
I am trying to calculate the amount of time a zip code temperature will drop to 0 or below on any given day. On the 13th, it only happens for a very short amount of time so we don't really care. I want to know how to calculate the number of minutes this happens on the 14th, since it looks like a significantly (and consistently) cold day.
I want the query to add two more columns.
The first column added would be the time difference between the rows on a given date. So row 3- row 2=40 mins and row 4-row3=60 mins.
The second column would total the amount of minutes for a whole day the minutes the temperature has dropped to 0 or below. Here row 2-4 would be ignored. From row 5-8, total time that the temperature was 0 or below would be about 90 mins
It should end up looking like this:
DATE TEMPERATURE MINUTES_DIFFERENCE TOTAL_MINUTES
2012-01-13 23:15:00 UTC 0 0 0
2012-01-14 01:35:00 UTC 5 140 0
2012-01-14 02:15:00 UTC 6 40 0
2012-01-14 03:15:00 UTC 8 60 0
2012-01-14 04:15:00 UTC 0 60 60
2012-01-14 04:55:00 UTC 0 30 90
2012-01-14 05:15:00 UTC-2 20 110
2012-01-14 05:35:00 UTC 0 20 130
Use below
select *,
sum(minutes_difference) over(order by date) total_minutes
from (
select *,
ifnull(timestamp_diff(timestamp(date), lag(timestamp(date)) over(order by date), minute), 0) as minutes_difference
from your_table
)
if applied to sample data in your question - output is
Update to answer updated question
select * except(new_grp, grp),
sum(if(temperature > 0, 0, minutes_difference)) over(partition by grp order by date) total_minutes
from (
select *, countif(new_grp) over(order by date) as grp
from (
select *,
ifnull(timestamp_diff(timestamp(date), lag(timestamp(date)) over(order by date), minute), 0) as minutes_difference,
ifnull(((temperature <= 0) and (lag(temperature) over(order by date) > 0)) or
((temperature > 0) and (lag(temperature) over(order by date) <= 0)), true) as new_grp
from your_table
)
)
with output

Creating a Time Dimension table with Intervals in Oracle

What is the easiest way to create a table in oracle to get the output as shown below;
Time Key
5 Minute Interval
10 Minute Interval
15 Minute Interval
100
12:00:00
12:10:00
12:15:00
101
12:05:00
12:10:00
12:15:00
102
12:10:00
12:20:00
12:15:00
103
12:15:00
12:20:00
12:30:00
The hours will be displayed in 24 hour format and will be used to join the time key onto a fact table to be loaded into a Microsoft Analysis Tabular Model.
Seems that you need a row generator. Here's an example.
Date format (just to know what you're looking at):
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
Query (creates 10 rows of data; change value in line #9 for more (or less) rows):
SQL> with temp (time_key, datum) as
2 (select 99, trunc(sysdate) datum from dual)
3 select
4 time_key + level time_key,
5 datum + ( 5 * (level - 1)) / (24 * 60) five_min,
6 datum + (10 * (level - 1)) / (24 * 60) ten_min,
7 datum + (15 * (level - 1)) / (24 * 60) fifteen_min
8 from temp
9 connect by level <= 10;
TIME_KEY FIVE_MIN TEN_MIN FIFTEEN_MIN
---------- ------------------- ------------------- -------------------
100 04.01.2021 00:00:00 04.01.2021 00:00:00 04.01.2021 00:00:00
101 04.01.2021 00:05:00 04.01.2021 00:10:00 04.01.2021 00:15:00
102 04.01.2021 00:10:00 04.01.2021 00:20:00 04.01.2021 00:30:00
103 04.01.2021 00:15:00 04.01.2021 00:30:00 04.01.2021 00:45:00
104 04.01.2021 00:20:00 04.01.2021 00:40:00 04.01.2021 01:00:00
105 04.01.2021 00:25:00 04.01.2021 00:50:00 04.01.2021 01:15:00
106 04.01.2021 00:30:00 04.01.2021 01:00:00 04.01.2021 01:30:00
107 04.01.2021 00:35:00 04.01.2021 01:10:00 04.01.2021 01:45:00
108 04.01.2021 00:40:00 04.01.2021 01:20:00 04.01.2021 02:00:00
109 04.01.2021 00:45:00 04.01.2021 01:30:00 04.01.2021 02:15:00
10 rows selected.
SQL>
In Oracle, there's no "time" datatype. We use date and it consists of both date AND time. Your example shows that you want time only; well, you can't have it, not as a date datatype. You can use e.g. TO_CHAR function on it (and fetch only time component). I wouldn't recommend you to store those values as strings into varchar2 datatype column as nothing prevents you (or someone else) to put e.g. 12:3f:75 into it, and that certainly isn't valid time value.
So, you'd then:
SQL> create table test as
2 with temp (time_key, datum) as
3 (select 99, trunc(sysdate) datum from dual)
4 select
5 time_key + level time_key,
6 datum + ( 5 * (level - 1)) / (24 * 60) five_min,
7 datum + (10 * (level - 1)) / (24 * 60) ten_min,
8 datum + (15 * (level - 1)) / (24 * 60) fifteen_min
9 from temp
10 connect by level <= 10;
Table created.
SQL> select time_key,
2 to_char(five_min, 'hh24:mi:ss') five_min
3 from test;
TIME_KEY FIVE_MIN
---------- --------
100 00:00:00
101 00:05:00
102 00:10:00
103 00:15:00
104 00:20:00
105 00:25:00
106 00:30:00
107 00:35:00
108 00:40:00
109 00:45:00
10 rows selected.
SQL>
To answer question T. Peter posted as a comment: I don't know for other databases, but - principle that should work elsewhere is to use a cross join (Cartesian product) with a subquery that returns "a lot of rows". In Oracle, ALL_OBJECTS is such a table. It isn't indefinite; in my sample schema, it contains ~8000 rows. For example (see lines #8 - 10):
SQL> with temp (time_key, datum) as
2 (select 99, trunc(sysdate) datum from dual)
3 select
4 time_key + rn time_key,
5 datum + ( 5 * (rn - 1)) / (24 * 60) five_min,
6 datum + (10 * (rn - 1)) / (24 * 60) ten_min,
7 datum + (15 * (rn - 1)) / (24 * 60) fifteen_min
8 from temp cross join (select rownum rn
9 from all_tables
10 where rownum <= 10
11 );
TIME_KEY FIVE_MIN TEN_MIN FIFTEEN_MIN
---------- ------------------- ------------------- -------------------
100 04.01.2021 00:00:00 04.01.2021 00:00:00 04.01.2021 00:00:00
101 04.01.2021 00:05:00 04.01.2021 00:10:00 04.01.2021 00:15:00
<snip>
Basically, keyword here is "row generator". I suggest you Google for it and add database name you use.
You can use a recursive sub-query factoring clause and get the time values using INTERVAL DAY TO SECOND data type:
CREATE TABLE table_name ( time_key, five_minute, ten_minute, fifteen_minute ) AS
WITH data ( time_key, five_minute, ten_minute, fifteen_minute, num_rows ) AS (
SELECT 100,
INTERVAL '12:00' HOUR TO MINUTE,
INTERVAL '12:00' HOUR TO MINUTE,
INTERVAL '12:00' HOUR TO MINUTE,
4
FROM DUAL
UNION ALL
SELECT time_key + 1,
five_minute + INTERVAL '5' MINUTE,
ten_minute + INTERVAL '10' MINUTE,
fifteen_minute + INTERVAL '15' MINUTE,
num_rows - 1
FROM data
WHERE num_rows > 1
)
SELECT time_key,
five_minute,
ten_minute,
fifteen_minute
FROM data;
Then the table contains:
TIME_KEY | FIVE_MINUTE | TEN_MINUTE | FIFTEEN_MINUTE
-------: | :---------------------------- | :---------------------------- | :----------------------------
100 | +000000000 12:00:00.000000000 | +000000000 12:00:00.000000000 | +000000000 12:00:00.000000000
101 | +000000000 12:05:00.000000000 | +000000000 12:10:00.000000000 | +000000000 12:15:00.000000000
102 | +000000000 12:10:00.000000000 | +000000000 12:20:00.000000000 | +000000000 12:30:00.000000000
103 | +000000000 12:15:00.000000000 | +000000000 12:30:00.000000000 | +000000000 12:45:00.000000000
db<>fiddle here

BigQuery - A way to generate timestamps based on hour/minute/seconds?

Is there a way to generate sequential timestamps in BigQuery that is focused on hours, minutes, and seconds?
In BigQuery you can generate sequential dates by:
select *
FROM UNNEST(GENERATE_DATE_ARRAY('2016-10-18', '2016-10-19', INTERVAL 1 DAY)) as day
This will generate the dates from 2016-10-18 to 2016-10-19 in date intervals
Row day
1 2016-10-18
2 2016-10-19
But let's say I want intervals in 15 minutes or 5 minutes, is there a way to do that?
First, I would recommend "starring" the feature request for GENERATE_TIMESTAMP_ARRAY to express interest in having a function like this. Given GENERATE_ARRAY, though, the best option currently is to use a query of this form:
SELECT TIMESTAMP_ADD('2018-04-01', INTERVAL 15 * x MINUTE)
FROM UNNEST(GENERATE_ARRAY(0, 13)) AS x;
If you want a minute-based GENERATE_TIMESTAMP_ARRAY equivalent, you can use a UDF like this:
CREATE TEMP FUNCTION GenerateMinuteTimestampArray(
t0 TIMESTAMP, t1 TIMESTAMP, minutes INT64) AS (
ARRAY(
SELECT TIMESTAMP_ADD(t0, INTERVAL minutes * x MINUTE)
FROM UNNEST(GENERATE_ARRAY(0, TIMESTAMP_DIFF(t1, t0, MINUTE))) AS x
)
);
SELECT ts
FROM UNNEST(GenerateMinuteTimestampArray('2018-04-01', '2018-04-01 12:00:00', 15)) AS ts;
This returns a timestamp for each 15-minute interval between midnight and 12 PM on April 1.
Update: You can now use the GENERATE_TIMESTAMP_ARRAY function in BigQuery. If you want to generate timestamps at intervals of 15 minutes, for example, you can use:
SELECT GENERATE_TIMESTAMP_ARRAY('2016-10-18', '2016-10-19', INTERVAL 15 MINUTE);
Epochs seems like the way to go.
But requires to convert date to epoch first.
select TIMESTAMP_MICROS(CAST(day * 1000000 as INT64))
FROM UNNEST(GENERATE_ARRAY(1522540800, 1525132799, 900)) as day
Row f0_
1 2018-04-01 00:00:00.000 UTC
2 2018-04-01 00:15:00.000 UTC
3 2018-04-01 00:30:00.000 UTC
4 2018-04-01 00:45:00.000 UTC
5 2018-04-01 01:00:00.000 UTC
6 2018-04-01 01:15:00.000 UTC
7 2018-04-01 01:30:00.000 UTC
8 2018-04-01 01:45:00.000 UTC
9 2018-04-01 02:00:00.000 UTC
10 2018-04-01 02:15:00.000 UTC
11 2018-04-01 02:30:00.000 UTC
12 2018-04-01 02:45:00.000 UTC
13 2018-04-01 03:00:00.000 UTC

Extract hours as 1 - 48 from half hour interval times

I have the below data.
0:00:00
0:30:00
1:00:00
1:30:00
2:00:00
2:30:00
3:00:00
3:30:00
4:00:00
4:30:00
5:00:00
5:30:00
6:00:00
6:30:00
I can extract the hour the using EXTRACT(HOUR FROM TIMESTAMP) but this will give me 24 hours.
But now I need to some different calculation where I can get numbers from 1-48 based on the time given.
Something like this:
0:00:00 1
0:30:00 2
1:00:00 3
1:30:00 4
2:00:00 5
2:30:00 6
3:00:00 7
3:30:00 8
4:00:00 9
4:30:00 10
6:00:00 13
6:30:00 14
Note the skipped 11 and 12, for the absent values 5:00 and 5:30.
Is there any possibilities that I can get that result in PostgreSQL?
Simply use formula 1 + extract(hour from 2 * tm) - it gives your expected result exactly - obligatory SQLFiddle.
This will give you a double precision result, that you can round to whatever you want:
2 * (EXTRACT(HOUR FROM t) + EXTRACT(MINUTE FROM t) / 60) + 1
EDIT:
Or, as #CraigRinger suggested:
EXTRACT(EPOCH FROM t) / 1800 + 1
For the later, t needs to be TIME, not TIMESTAMP. Use cast if needed.
UPDATE: This will work with INTERVALs too.
SELECT 2 * (EXTRACT(HOUR FROM t) + EXTRACT(MINUTE FROM t) / 60) + 1,
EXTRACT(EPOCH FROM t) / 1800 + 1
FROM (VALUES (time '4:30:00'), (time '7:24:31'), (time '8:15:00')) as foo(t)
-- results:
?column? | ?column?
---------+---------
10 | 10
15.8 | 15.8172222222222
17.5 | 17.5
But as you wrote, there will be no edge cases (when the time cannot be divided with 30 minutes).
select
case
when date_time_field_of_interest::time >= '00:00:00' and date_time_field_of_interest::time < '00:30:00' then 1
when date_time_field_of_interest::time >= '00:30:00' and date_time_field_of_interest::time < '01:00:00' then 2
....
end
from your_table;

SQL code for Comparing date fields in different rows and combining the results

I need help for proper Oracle SQL code to combine rows for a crystal reports command object. This is a part of the bigger query I'm working on and got stuck for the past couple of days.
for eg. if the columns are like below
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/01/2012 10:00:00 am
151 01/01/2012 11:00:00 am 01/02/2012 08:00:00 am
151 01/02/2012 11:00:00 am 01/02/2012 01:00:00 pm
151 01/03/2012 08:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/14/2012 07:00:00 am
167 01/14/2012 11:30:00 am 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
Within a PatId, the code should compare the Out_time of one row to the In_time of the next row, and check whether the time gap is greater than 48 hours. If not, then it is considered part of the same visit. I want one result row per PatID & visit, with min(In_time) and max(Out_time). The time span of the visit (result row) itself may be greater than 48 hours.
For this example, for PatId 151 the time difference between the out_time of 1st row and In_time of 2nd row is less than 48 hours. The difference between Out_time of second row and In_time of 3rd row, as well as between the 3rd and 4th rows, is also less than 48 hours. After this the gap between Out_time of the 4th row and In_time of 5th row is greater than 48 hours. The result for PatId 151 should be as below and same for EmpId 167, the chaining should continue until a gap greater than 48 hours is found.
So the result for the above table should be displayed as,
PatId In_time Out_time
151 01/01/2012 07:00:00 am 01/03/2012 03:00:00 pm
151 01/06/2012 03:30:00 pm 01/09/2012 07:00:00 am
167 01/03/2012 01:30:00 pm 01/09/2012 07:00:00 am
167 01/13/2012 03:30:00 pm 01/15/2012 11:30:00 am
167 01/18/2012 12:00:00 pm 01/19/2012 03:00:00 am
I could not get the logic on how to compare and merge rows.
Thanks in Advance, Abhi
General example of subtracting time - copy/paste to see the output. This example will give you differences in hours, minutes, seconds between two dates. The basic formula is (end_date - start_date) * 86400 (number of seconds in 24 hrs)...:
SELECT trunc(mydate / 3600) hr
, trunc(mod(mydate, 3600) / 60) mnt
, trunc(mod(mydate, 3600) / 60 /60) sec
FROM
(
SELECT (to_date('01/03/2012 10:00:00', 'mm/dd/yyyy hh24:mi:ss') -
to_date('01/01/2012 07:00:00', 'mm/dd/yyyy hh24:mi:ss')) * 86400 mydate
FROM dual
)
/
HR | MNT | SEC
---------------
51 | 0 | 0
You need to check your example and logic. I could not understand what needs to be comnpared with what...