【问题标题】:Compute average of data between time period in Oracle sql在Oracle sql中计算时间段之间的数据平均值
【发布时间】:2016-11-24 20:59:33
【问题描述】:

我有一个名为 IMETERDATA 的表:

DEVNAME VARCHAR2(25)
DEVID   VARCHAR2(8)
USEDATE TIMESTAMP(6)
INSTANTPOWER    NUMBER(3,0)
TOTALENERGY NUMBER(7,4)
ROWNUMBER   NUMBER(4,0)

我想计算并显示每 2 小时的 Totalenergy 平均值。例如,如果我有特定日期的数据(例如 2016 年 11 月 22 日),我想计算以下时段的 Totalenergy 平均值:12am-2am、2am-4am .... 10pm-12pm。我想计算指定间隔的所有日期的平均值。到目前为止我做了什么:

    select to_number(to_char(USEDATE, 'HH24')) as "HOUR", 
    avg(TOTALENERGY) as "AVERAGE", TRUNC(USEDATE, 'DD') as "DATE"
    from IMETERDATA 
    WHERE TRUNC(USEDATE) in (select DISTINCT(TRUNC(USEDATE, 'DD')) 
    from IMETERDATA) and (to_number(to_char(USEDATE, 'HH24')) >= 12 and to_number(to_char(USEDATE, 'HH24')) < 14 )
    group by to_number(to_char(USEDATE, 'HH24')), TRUNC(USEDATE, 'DD'); 

此查询仅提供从中午 12 点到下午 2 点的平均值。如何计算 24 小时?我想要从上午 12 点到晚上 11.59 的结果,间隔 2 小时:

12AM - 2AM ---> 58.50
2AM - 4AM ----> 60.35
   ...
10PM - 11.59PM --> 40.35

【问题讨论】:

  • 您需要使用start_time, end_time 创建一个小时范围表,然后加入您的查询,以便每小时获得一个范围。然后按范围分组
  • 嗯。我可以在不创建另一个表的情况下做到这一点吗?当循环更改小时时,我尝试在 .psp 文件中执行,但它很混乱。
  • 什么是psp?您可以使用WITH 来使用时间查询
  • @JuanCarlosOropeza 我正在使用 PSP (PL/SQL Server Page) 在浏览器中显示查询。

标签: sql oracle oracle11g


【解决方案1】:

嗯。我可以在不创建另一个表的情况下这样做吗?

当然。使用如下查询(此示例生成 2 天的 2 小时周期):

ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy-mm-dd hh24:mi'
;
SELECT date '2016-11-22' + NUMTODSINTERVAL( 2 * (level - 1), 'HOUR' ) as period_start
FROM dual
CONNECT BY LEVEL <= 2 * 12 ; -- 2 days of 12 "two hours" periods

PERIOD_START   
----------------
2016-11-22 00:00
2016-11-22 02:00
2016-11-22 04:00
2016-11-22 06:00
2016-11-22 08:00
2016-11-22 10:00
2016-11-22 12:00
2016-11-22 14:00
2016-11-22 16:00
2016-11-22 18:00
2016-11-22 20:00
2016-11-22 22:00
2016-11-23 00:00
2016-11-23 02:00
2016-11-23 04:00
2016-11-23 06:00
2016-11-23 08:00
2016-11-23 10:00
2016-11-23 12:00
2016-11-23 14:00
2016-11-23 16:00
2016-11-23 18:00
2016-11-23 20:00
2016-11-23 22:00

 24 rows selected 

然后将上述查询的结果加入到您的表中并计算平均值

SELECT x.PERIOD_START,
       AVG( i.TOTALENERGY )
FROM (
   the_above_query
) x
JOIN IMETERDATA i
ON i.USEDATE >= x.PERIOD_START AND i.USEDATE < x.PERIOD_START + interval '2' hour
GROUP BY x.PERIOD_START

【讨论】:

  • 感谢您的回复。如果我有很多天怎么办?如何选择 30 天的期限?
  • 举几个例子:30天的周期 --> CONNECT BY LEVEL &lt;= 30 * 12 ;, 300天的周期 => CONNECT BY LEVEL &lt;= 300 * 12 ; , 300万天的周期 ==> CONNECT BY LEVEL &lt;= 3000000 * 12 ;
【解决方案2】:

看看Analytic Functions: windowing_clause,你可以直接做。

select USEDATE, 
    AVG(TOTALENERGY) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as AVERAGE,
    MIN(USEDATE) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as INTERVAL_START,
    MAXUSEDATE) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as INTERVAL_END
from IMETERDATA;

此查询为您提供每次 +/- 1 小时(即 2 小时)的所有平均值。 如果您只需要给定时间的时间,您可以使用

with t as 
   (select USEDATE, 
      AVG(TOTALENERGY) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as AVERAGE,
      MIN(USEDATE) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as INTERVAL_START,
      MAXUSEDATE) OVER (ORDER BY USEDATE RANGE BETWEEN INTERVAL '1' HOUR PRECEDING AND INTERVAL '1' HOUR FOLLOWING) as INTERVAL_END
    from IMETERDATA)
select *
from t
where USEDATE = TRUNC(USEDATE, 'HH')
   AND EXTRACT(HOUR FROM USEDATE) IN (1,3,5,7,...);

你也可以用MOD(EXTRACT(HOUR FROM USEDATE), 1) = 1代替EXTRACT(HOUR FROM USEDATE) IN (1,3,5,7,...)

也许这不是您要寻找的 100%(您的问题在这方面不太清楚),但我假设您知道如何使用它。

【讨论】:

    猜你喜欢
    • 2017-10-13
    • 2021-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多