问题
If given the Average for 24 hours for each date in a year. I want to spread this hourly average to average at each minute. e.g. given
Date Time Average
01-Jan-15 23:00 20
02-Jan-15 00:00 50
02-Jan-15 01:00 30
I want the output to be calculated something as below ....
DateTime AVG_VALUE
01/01/2015 23:00:00 20
01/01/2015 23:01:00 20.5
01/01/2015 23:02:00 21
01/01/2015 23:03:00 21.5
01/01/2015 23:04:00 22
01/01/2015 23:05:00 22.5
01/01/2015 23:06:00 23
01/01/2015 23:07:00 23.5
01/01/2015 23:08:00 24
01/01/2015 23:09:00 24.5
01/01/2015 23:10:00 25
01/01/2015 23:11:00 25.5
01/01/2015 23:12:00 26
01/01/2015 23:13:00 26.5
01/01/2015 23:14:00 27
01/01/2015 23:15:00 27.5
01/01/2015 23:16:00 28
01/01/2015 23:17:00 28.5
01/01/2015 23:18:00 29
01/01/2015 23:19:00 29.5
01/01/2015 23:20:00 30
01/01/2015 23:21:00 30.5
01/01/2015 23:22:00 31
01/01/2015 23:23:00 31.5
01/01/2015 23:24:00 32
01/01/2015 23:25:00 32.5
01/01/2015 23:26:00 33
01/01/2015 23:27:00 33.5
01/01/2015 23:28:00 34
01/01/2015 23:29:00 34.5
01/01/2015 23:30:00 35
01/01/2015 23:31:00 35.5
01/01/2015 23:32:00 36
01/01/2015 23:33:00 36.5
01/01/2015 23:34:00 37
01/01/2015 23:35:00 37.5
01/01/2015 23:36:00 38
01/01/2015 23:37:00 38.5
01/01/2015 23:38:00 39
01/01/2015 23:39:00 39.5
01/01/2015 23:40:00 40
01/01/2015 23:41:00 40.5
01/01/2015 23:42:00 41
01/01/2015 23:43:00 41.5
01/01/2015 23:44:00 42
01/01/2015 23:45:00 42.5
01/01/2015 23:46:00 43
01/01/2015 23:47:00 43.5
01/01/2015 23:48:00 44
01/01/2015 23:49:00 44.5
01/01/2015 23:50:00 45
01/01/2015 23:51:00 45.5
01/01/2015 23:52:00 46
01/01/2015 23:53:00 46.5
01/01/2015 23:54:00 47
01/01/2015 23:55:00 47.5
01/01/2015 23:56:00 48
01/01/2015 23:57:00 48.5
01/01/2015 23:58:00 49
01/01/2015 23:59:00 49.5
02/01/2015 50
02/01/2015 00:01:00 49.66666667
02/01/2015 00:02:00 49.33333333
02/01/2015 00:03:00 49
02/01/2015 00:04:00 48.66666667
02/01/2015 00:05:00 48.33333333
The idea is to get the smooth incline or decline graph between two interval. In the output you can see the avg is gradually increasing with increasing minutes as we move from 20->50
Can this be achived using Oracle Query or some PL/SQL code?
回答1:
EDIT: Added union to include the final missing row
Some thing like this may work. Assuming the input data is in table a,
with b as
(select level-1 lev
from dual
connect by level <= 60
),
v as
(
select start_date, value current_value, lead(value) over (order by start_date) next_value
from a
)
select start_date+ (lev)/(24*60), (current_value*((60-(b.lev))/60) + next_value*(b.lev)/60) avg_value
from v, b
where v.next_value is not null
union
select start_date, current_value
from v
where v.next_value is null
order by 1
回答2:
You can use recursive subquery factoring to do the interval halving, and find the weighted average (or whatever this calculation is supposed to be finding) for each step:
with r (period_start, period_average, step, step_start, step_end, step_average) as (
select period_start,
period_average,
1,
period_start + ((lead(period_start) over (order by period_start) - period_start)/2),
lead(period_start) over (order by period_start) - 1/86400,
(period_average + lead(period_average) over (order by period_start))/2
from averages
union all
select period_start,
period_average,
r.step + 1,
case when r.step_start = period_start + 60/86400 then period_start
else trunc(period_start + ((r.step_start - period_start)/2) + 30/86400, 'MI')
end,
r.step_start - 1/86400,
case when r.step_start = period_start + 60/86400 then period_average
else (period_average + r.step_average)/2
end
from r
where r.step_start > r.period_start
)
--cycle step_start set is_cycle to 1 default 0
select * from r
where step_start is not null
order by step_start;
The anchor member gets the initial half-hour slot and the next period's average value, via lead()
, and uses those to calculate the initial (20+50)/2 etc.:
PERIOD_START PERIOD_AVERAGE STEP STEP_START STEP_END STEP_AVERAGE
---------------- -------------- ---- ---------------- ---------------- ------------
2015-01-01 06:00 20 1 2015-01-01 06:30 2015-01-01 06:59 35.00000
2015-01-01 07:00 50 1 2015-01-01 07:30 2015-01-01 07:59 45.00000
2015-01-01 08:00 40 1 2015-01-01 08:30 2015-01-01 08:59 35.00000
...
The recursive member then repeats that process but with the previous step's period length and calculated average. I've now made it stop when it reaches the last minute in the period.
So that gives you the intermediate result set:
PERIOD_START PERIOD_AVERAGE STEP STEP_START STEP_END STEP_AVERAGE
---------------- -------------- ---- ---------------- ---------------- ------------
2015-01-01 06:00 20 7 2015-01-01 06:00 2015-01-01 06:00 20.00000
2015-01-01 06:00 20 6 2015-01-01 06:01 2015-01-01 06:01 20.46875
2015-01-01 06:00 20 5 2015-01-01 06:02 2015-01-01 06:03 20.93750
2015-01-01 06:00 20 4 2015-01-01 06:04 2015-01-01 06:07 21.87500
2015-01-01 06:00 20 3 2015-01-01 06:08 2015-01-01 06:14 23.75000
2015-01-01 06:00 20 2 2015-01-01 06:15 2015-01-01 06:29 27.50000
2015-01-01 06:00 20 1 2015-01-01 06:30 2015-01-01 06:59 35.00000
2015-01-01 07:00 50 7 2015-01-01 07:00 2015-01-01 07:00 50.00000
2015-01-01 07:00 50 6 2015-01-01 07:01 2015-01-01 07:01 49.84375
2015-01-01 07:00 50 5 2015-01-01 07:02 2015-01-01 07:03 49.68750
2015-01-01 07:00 50 4 2015-01-01 07:04 2015-01-01 07:07 49.37500
2015-01-01 07:00 50 3 2015-01-01 07:08 2015-01-01 07:14 48.75000
2015-01-01 07:00 50 2 2015-01-01 07:15 2015-01-01 07:29 47.50000
2015-01-01 07:00 50 1 2015-01-01 07:30 2015-01-01 07:59 45.00000
2015-01-01 08:00 40 7 2015-01-01 08:00 2015-01-01 08:00 40.00000
2015-01-01 08:00 40 6 2015-01-01 08:01 2015-01-01 08:01 39.84375
2015-01-01 08:00 40 5 2015-01-01 08:02 2015-01-01 08:03 39.68750
2015-01-01 08:00 40 4 2015-01-01 08:04 2015-01-01 08:07 39.37500
2015-01-01 08:00 40 3 2015-01-01 08:08 2015-01-01 08:14 38.75000
2015-01-01 08:00 40 2 2015-01-01 08:15 2015-01-01 08:29 37.50000
2015-01-01 08:00 40 1 2015-01-01 08:30 2015-01-01 08:59 35.00000
You can then use another recursive CTE, or I think more simply a connect by
clause, to expand each of those steps into the appropriate number of minutes, each with the same 'average' value:
with r (period_start, period_average, step, step_start, step_end, step_average)
as (
...
)
select step_start + (level - 1)/24/60 as min_start, step_average
from r
where step_start is not null
connect by level <= (step_end - step_start) * 60 * 24 + 1
and prior step_start = step_start
and prior dbms_random.value is not null
order by min_start;
Which gives you:
MIN_START STEP_AVERAGE
---------------- ---------------------------------------
2015-01-01 06:00 20
2015-01-01 06:01 20.46875
2015-01-01 06:02 20.9375
2015-01-01 06:03 20.9375
2015-01-01 06:04 21.875
2015-01-01 06:05 21.875
2015-01-01 06:06 21.875
2015-01-01 06:07 21.875
2015-01-01 06:08 23.75
2015-01-01 06:09 23.75
...
2015-01-01 06:14 23.75
2015-01-01 06:15 27.5
2015-01-01 06:16 27.5
...
2015-01-01 06:29 27.5
2015-01-01 06:30 35
2015-01-01 06:31 35
...
2015-01-01 06:59 35
2015-01-01 07:00 50
2015-01-01 07:01 49.6875
2015-01-01 07:02 49.6875
2015-01-01 07:03 49.375
...
回答3:
You can use this query and change the hours to minutes. It works with any interval and will not fail on daylight savings days if this is a problem for you in your area.
This query returns Time of Max and Time of min, you can remove all of this in the final select statement.
In Oracle 11g how do you time weight average data hourly between two dates?
来源:https://stackoverflow.com/questions/31541384/how-to-spread-the-average-between-two-intervals-in-oracle