Create a table of time series data
create table time_data as
select * from (
select date'2025-02-01'
+ numtodsinterval ( level , 'minute' )
+ ( mod ( level, 17 ) / 60 / 24 )
+ ( sin ( level ) / 24 ) datetime
from dual
connect by level <= 200
union all
select date'2025-02-02'
+ ( level / 4 )
+ ( sin ( level ) / 24 ) datetime
from dual
connect by level <= 100
)
where datetime >= date'2025-02-01'
and datetime not between date'2025-02-01' + 15/24/60 and date'2025-02-01' + 19/24/60
order by datetime
Table created.
alter session set nls_date_format = 'DD-MON-YYYY HH24:MI'
Statement processed.
Group rows in 5-minute intervals
with rws as (
select date'2025-02-01' origin,
datetime,
1440 units_in_day,
5 stride_interval
from time_data
), buckets as (
select floor ( round ( ( datetime - origin ) * units_in_day, 9 ) / stride_interval ) bucket#,
r.*
from rws r
), intervals as (
select origin + ( bucket# * stride_interval / units_in_day ) start_datetime,
origin + ( ( bucket# + 1 ) * stride_interval / units_in_day ) end_datetime
from buckets
)
select count(*), start_datetime, end_datetime
from intervals
group by start_datetime, end_datetime
order by start_datetime
fetch first 5 rows only
COUNT(*) | START_DATETIME | END_DATETIME | 3 | 01-FEB-2025 00:00 | 01-FEB-2025 00:05 | 1 | 01-FEB-2025 00:05 | 01-FEB-2025 00:10 | 5 | 01-FEB-2025 00:10 | 01-FEB-2025 00:15 | 3 | 01-FEB-2025 00:20 | 01-FEB-2025 00:25 | 4 | 01-FEB-2025 00:25 | 01-FEB-2025 00:30 |
---|
Group rows in 10-minute intervals
select trunc ( datetime ) + (
floor (
round ( ( datetime - trunc ( datetime ) ) * 1440 / 10, 9 )
) * 10 / 1440
) start_datetime,
count (*)
from time_data
group by trunc ( datetime )
+ ( floor (
round ( ( datetime - trunc ( datetime ) ) * 1440 / 10, 9 )
) * 10 / 1440
)
order by start_datetime
fetch first 5 rows only
START_DATETIME | COUNT(*) | 01-FEB-2025 00:00 | 4 | 01-FEB-2025 00:10 | 5 | 01-FEB-2025 00:20 | 7 | 01-FEB-2025 00:30 | 7 | 01-FEB-2025 00:40 | 3 |
---|
Group rows in N-minute intervals
declare
stride integer := 5;
units_in_day integer := 1440;
begin
for rws in (
with rws as (
select trunc ( datetime ) origin,
datetime,
units_in_day units_in_day,
stride stride_interval
from time_data
), buckets as (
select floor ( round ( ( datetime - origin ) * units_in_day, 9 ) / stride_interval ) bucket#,
rws.*
from rws
), intervals as (
select origin + ( bucket# * stride_interval / units_in_day ) start_datetime,
origin + ( ( bucket# + 1 ) * stride_interval / units_in_day ) end_datetime
from buckets
)
select count(*) row#, start_datetime
from intervals
group by start_datetime
order by start_datetime
fetch first 5 rows only
) loop
dbms_output.put_line ( rws.start_datetime || ' - ' || rws.row# );
end loop;
end;
Statement processed.
01-FEB-2025 00:00 - 3
01-FEB-2025 00:05 - 1
01-FEB-2025 00:10 - 5
01-FEB-2025 00:20 - 3
01-FEB-2025 00:25 - 4
Group rows into 5 minute intervals with time_bucket
select count(*),
time_bucket (
datetime, interval '5' minute, date'2025-02-01'
) start_date,
time_bucket (
datetime, interval '5' minute, date'2025-02-01', end
) end_date
from time_data
group by start_date, end_date
order by start_date;
Group rows in 5-minute intervals including missing times
declare
duration_in_minutes integer := 5;
start_time varchar2(20) := '01-FEB-2025 00:00';
number_of_intervals integer := 12;
begin
for rws in (
with times as (
select to_date ( start_time, 'DD-MON-YYYY HH24:MI' )
+ ( ( level - 1 ) * duration_in_minutes / 1440 ) dt
from dual
connect by level <= number_of_intervals
), intervals as (
select dt start_date,
dt + ( duration_in_minutes / 1440 ) end_date
from times
)
select start_date, end_date, count ( datetime ) row#
from intervals i
left join time_data t
on start_date <= datetime
and datetime < end_date
group by start_date, end_date
order by start_date
fetch first 5 rows only
) loop
dbms_output.put_line ( rws.start_date || ' - ' || rws.row# );
end loop;
end;
Statement processed.
01-FEB-2025 00:00 - 3
01-FEB-2025 00:05 - 1
01-FEB-2025 00:10 - 5
01-FEB-2025 00:15 - 0
01-FEB-2025 00:20 - 3
Group rows in N-minute intervals starting from source data
declare
duration_in_minutes integer := 5;
number_of_intervals integer := 12;
begin
for rws in (
with start_date as (
select min ( datetime ) start_date,
duration_in_minutes / 1440 time_interval
from time_data
), intervals as (
select start_date + ( ( level - 1 ) * time_interval ) start_date,
start_date + ( ( level ) * time_interval ) end_date
from start_date
connect by level <= number_of_intervals
)
select start_date, count ( datetime ) row#
from intervals
left join time_data
on start_date <= datetime
and datetime < end_date
group by start_date
order by start_date
) loop
dbms_output.put_line ( rws.start_date || ' - ' || rws.row# );
end loop;
end;
Statement processed.
01-FEB-2025 00:01 - 3
01-FEB-2025 00:06 - 2
01-FEB-2025 00:11 - 4
01-FEB-2025 00:16 - 2
01-FEB-2025 00:21 - 2
01-FEB-2025 00:26 - 4
01-FEB-2025 00:31 - 3
01-FEB-2025 00:36 - 3
01-FEB-2025 00:41 - 2
01-FEB-2025 00:46 - 3
01-FEB-2025 00:51 - 7
01-FEB-2025 00:56 - 4
Group rows in N-minute intervals with variable gaps
declare
duration_in_minutes integer := 5;
begin
for rws in (
select *
from time_data
match_recognize (
order by datetime
measures
init.datetime as interval_start,
init.datetime
+ numtodsinterval ( duration_in_minutes, 'minute' ) as interval_end,
count(*) as row#
pattern ( init time_interval* )
define
time_interval as datetime <
init.datetime + numtodsinterval ( duration_in_minutes, 'minute' )
)
fetch first 5 rows only
) loop
dbms_output.put_line ( rws.interval_start || ' - ' || rws.row# );
end loop;
end;
Statement processed.
01-FEB-2025 00:01 - 3
01-FEB-2025 00:06 - 2
01-FEB-2025 00:13 - 4
01-FEB-2025 00:20 - 4
01-FEB-2025 00:26 - 4
Combine all rows within N-minutes of the previous row
declare
duration_in_minutes integer := 5;
begin
for rws in (
select *
from time_data
match_recognize (
order by datetime
measures
init.datetime as interval_start,
init.datetime
+ numtodsinterval ( duration_in_minutes, 'minute' ) as interval_end,
count(*) as row#
pattern ( init time_interval* )
define
time_interval as datetime <
prev ( datetime ) + numtodsinterval ( duration_in_minutes, 'minute' )
)
fetch first 5 rows only
) loop
dbms_output.put_line ( rws.interval_start || ' - ' || rws.row# );
end loop;
end;
Statement processed.
01-FEB-2025 00:01 - 9
01-FEB-2025 00:20 - 11
01-FEB-2025 00:37 - 5
01-FEB-2025 00:49 - 23
01-FEB-2025 01:14 - 120