我有事件数据的表包含两个日期: 1)活动开始日期(例如2017-03-01 05:30:00) 2)活动结束日期(例如2017-03-01 06:10:00)
我需要创建包含结构的报告,其中数据是在24小时时间间隔内分组给定年 - 日和小时的所有事件的总和,如下所示:
两行:
Id | Start date | End date
Event 1 | 2017-03-01 07:45 | 2017-03-01 08:15
Event 2 | 2017-03-01 08:25 | 2017-03-01 08:40
查询结果:
Year-Month-Day | Hours | (Activity time in seconds or minutes - here minutes)
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 30
2017-03-01 | 09 | 00
...
在Oracle SQL中执行此操作是否优雅?我在第一时间写了一些psudocode,(我在开始和结束时间之间计算差异,检查受影响的小时数,并分配到正确的时间间隔),但是可能存在更多本机和更好的性能解决方案 - 比如聚合函数等?< / p>
感谢您的帮助。
答案 0 :(得分:2)
这是一个可以满足您需求的查询。 但请注意,这仅适用于在100万分钟内完成的事件,即大约2年。
WITH event
AS (SELECT 'Event 1' AS id,
'2017-03-01 07:45' AS start_date,
'2017-03-01 08:15' AS end_date
FROM DUAL
UNION ALL
SELECT 'Event 2' AS id,
'2017-03-01 08:25' AS start_date,
'2017-03-01 08:40' AS end_date
FROM DUAL),
add_mins
AS (SELECT LEVEL
- 1
AS add_min
FROM DUAL
CONNECT BY LEVEL <= 1000000),
hrs_in_day
AS (SELECT LEVEL
- 1
AS hr
FROM DUAL
CONNECT BY LEVEL <= 24),
all_days_hrs
AS (SELECT *
FROM (SELECT TO_CHAR (
(first_start_day
+ LEVEL
- 1),
'YYYY-MM-DD'
)
AS curr_day
FROM (SELECT MIN (curr_day) AS first_start_day,
MAX (curr_day) AS last_end_day
FROM (SELECT TO_TIMESTAMP (start_date, 'YYYY-MM-DD HH24:MI')
AS curr_day
FROM event
UNION
SELECT TO_TIMESTAMP (end_date, 'YYYY-MM-DD HH24:MI')
AS curr_day
FROM event))
CONNECT BY (first_start_day
+ LEVEL
- 1) < last_end_day),
hrs_in_day)
SELECT hl.curr_day AS year_month_day,
LPAD (hl.hr, 2, '0') AS hours,
COUNT (h.curr_hr) AS activity_duration_in_min
FROM all_days_hrs hl
LEFT JOIN
(SELECT id,
start_time,
end_time,
curr_time,
TO_CHAR (curr_time, 'YYYY-MM-DD') AS year_month_day,
EXTRACT (HOUR FROM curr_time) AS curr_hr
FROM (SELECT id,
start_time,
end_time,
b.add_min,
start_time
+ NUMTODSINTERVAL (b.add_min, 'minute')
AS curr_time
FROM (SELECT id,
start_time,
end_time,
EXTRACT (DAY FROM dur_interval) * 1440
+ EXTRACT (HOUR FROM dur_interval) * 60
+ EXTRACT (MINUTE FROM dur_interval)
AS duration_in_min
FROM (SELECT id,
start_time,
end_time,
(end_time
- start_time)
AS dur_interval
FROM (SELECT id,
TO_TIMESTAMP (
start_date,
'YYYY-MM-DD HH24:MI'
)
AS start_time,
TO_TIMESTAMP (
end_date,
'YYYY-MM-DD HH24:MI'
)
AS end_time
FROM event))) a,
add_mins b
WHERE b.add_min < a.duration_in_min)) h
ON (hl.curr_day = h.year_month_day
AND hl.hr = h.curr_hr)
GROUP BY hl.curr_day,
hl.hr
ORDER BY year_month_day NULLS FIRST,
hl.hr;
虽然有点慢。我没有花时间考虑性能。 但它的确有效。这是输出。
Year-Month-day | Hours | Activity_Duration_in_min
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 30
2017-03-01 | 09 | 0
2017-03-01 | 10 | 0
2017-03-01 | 11 | 0
2017-03-01 | 12 | 0
2017-03-01 | 13 | 0
2017-03-01 | 14 | 0
2017-03-01 | 15 | 0
2017-03-01 | 16 | 0
2017-03-01 | 17 | 0
2017-03-01 | 18 | 0
2017-03-01 | 19 | 0
2017-03-01 | 20 | 0
2017-03-01 | 21 | 0
2017-03-01 | 22 | 0
2017-03-01 | 23 | 0
如果我们更改“事件2”的结束日期&#39;到2017-03-02(即活动持续了一天,15分钟和第8小时40分钟)我们可以看到输出变化以反映48小时的持续时间。
Year-Month-day | Hours | Activity_Duration_in_min
2017-03-01 | 00 | 0
2017-03-01 | 01 | 0
2017-03-01 | 02 | 0
2017-03-01 | 03 | 0
2017-03-01 | 04 | 0
2017-03-01 | 05 | 0
2017-03-01 | 06 | 0
2017-03-01 | 07 | 15
2017-03-01 | 08 | 50
2017-03-01 | 09 | 60
2017-03-01 | 10 | 60
2017-03-01 | 11 | 60
2017-03-01 | 12 | 60
2017-03-01 | 13 | 60
2017-03-01 | 14 | 60
2017-03-01 | 15 | 60
2017-03-01 | 16 | 60
2017-03-01 | 17 | 60
2017-03-01 | 18 | 60
2017-03-01 | 19 | 60
2017-03-01 | 20 | 60
2017-03-01 | 21 | 60
2017-03-01 | 22 | 60
2017-03-01 | 23 | 60
2017-03-02 | 00 | 60
2017-03-02 | 01 | 60
2017-03-02 | 02 | 60
2017-03-02 | 03 | 60
2017-03-02 | 04 | 60
2017-03-02 | 05 | 60
2017-03-02 | 06 | 60
2017-03-02 | 07 | 60
2017-03-02 | 08 | 40
2017-03-02 | 09 | 0
2017-03-02 | 10 | 0
2017-03-02 | 11 | 0
2017-03-02 | 12 | 0
2017-03-02 | 13 | 0
2017-03-02 | 14 | 0
2017-03-02 | 15 | 0
2017-03-02 | 16 | 0
2017-03-02 | 17 | 0
2017-03-02 | 18 | 0
2017-03-02 | 19 | 0
2017-03-02 | 20 | 0
2017-03-02 | 21 | 0
2017-03-02 | 22 | 0
2017-03-02 | 23 | 0