如何在oracle中传播两个区间之间的平均值

时间:2015-07-21 14:04:57

标签: sql oracle oracle11g intervals

如果给出一年中每个日期的平均24小时。我希望将每小时平均值传播到每分钟的平均值。 例如给定

Date        Time    Average
01-Jan-15   23:00   20
02-Jan-15   00:00   50
02-Jan-15   01:00   30

我希望输出计算如下......

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

想法是在两个间隔之间获得平滑的倾斜或下降图。在输出中,您可以看到随着我们从20-> 50

移动,平均值逐渐增加

使用Oracle Query或某些PL / SQL代码可以实现这个目标吗?

3 个答案:

答案 0 :(得分:1)

您可以使用recursive subquery factoring进行间隔减半,并找到每个步骤的加权平均值(或该计算应该找到的任何内容):

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;

锚点成员通过lead()获取初始半小时时段和下一时段的平均值,并使用这些来计算初始时间(20 + 50)/ 2等:

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
...

递归成员然后重复该过程但是使用上一步的周期长度和计算的平均值。我现在已经停止了这段时间的最后一分钟。

这样就可以得到中间结果集:

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

然后,您可以使用另一个递归CTE,或者我更简单地考虑connect by子句,将每个步骤扩展到适当的分钟数,每个步骤具有相同的“平均”值:

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;

这给了你:

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
...

答案 1 :(得分:1)

编辑:添加了联合以包含最后遗失的行

这样的事情可能有用。假设输入数据在表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 :(得分:0)

您可以使用此查询并将小时数更改为分钟数。它适用于任何时间间隔,如果您所在地区出现问题,夏令时不会失败。

此查询返回最大时间和最小时间,您可以在最终的选择语句中删除所有这些。

In Oracle 11g how do you time weight average data hourly between two dates?