显示特定时间范围的值

Display values for specific time-frame

当我运行低于select时:

select name, time, value from table1 where name like '%Z' or '%V'

我得到了结果:

我需要做两件事:

1) 查询将每小时 运行,所以如果我们有 12.00.00PM,范围应该在(11 点和 12> PM 之间,如果是 02.00。 00AM 范围将是(01 和 02> AM

2) 第二件事是将以 '%Z' 或 '%V' 结尾的名称的 avg(value) 显示到 一行, 但分为 两列

以下是理想结果的示例,查询时间为 运行 下午 12.00.00:

select T1.Z, T1.V from (
(select avg(values) from table1 where name like '%Z' and time between sysdate and sysdate - interval '1' group by INSTR(name,'Z')) Z,
(select avg(values) from table1 where name like '%V' and time between sysdate and sysdate - interval '1' group by INSTR(name,'V')) V ) T1

你要求的是三件事,可以认为是三步。获取时间 window 非常简单,只是因为您的列是时间戳而不是日期而稍微复杂一些。您暗示这将在整点 运行,但它可能会稍晚一些 - 也许一两秒? - 所以考虑到这一点可能更安全。您可以使用 the trunc() function to modify a date value to the required precision, so to only look at the current hour you would truncate to HH[24]. You can then cast that back to a timestamp. And you can use interval arithmetic 查找之前的小时:

alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS';
alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF3';
alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF3 TZR';

select systimestamp,
  trunc(systimestamp, 'HH24') as a,
  cast(trunc(systimestamp, 'HH24') as timestamp) as b,
  cast(trunc(systimestamp, 'HH24') as timestamp) - interval '1' hour as c
from dual;

SYSTIMESTAMP                   A                   B                       C                      
------------------------------ ------------------- ----------------------- -----------------------
2017-03-01 09:25:39.342 +00:00 2017-03-01 09:00:00 2017-03-01 09:00:00.000 2017-03-01 08:00:00.000

alter session命令只是控制不同数据类型的显示方式,以供比较。 (不要依赖实际代码中的 NLS 设置;使用 to_char() 将日期时间值最终格式化为字符串)。

请注意,t运行cation 的结果现在是一个日期(该输出中的 A),因此我将其转换回时间戳 (B)。你想要的范围本质上是 time >= A and time < B。您可以使用 sysdate 而不是 systimestamp 作为 trunc().

的输入

对于您使用 systimestampsysdate 的样本数据将找不到任何东西,因此我将使用一个假的固定时间来处理其余部分,在 CTE 中生成以进行分离。在我使用 CTE 中的 now 的地方,您可以使用 systimestamp 或 sysdate。

第二部分是获取该时间段内每个名称的平均值。这是简单的聚合:

with fake_time(now) as (
  select timestamp '2017-02-10 13:01:07' from dual
)
select name,
  avg(value) as avg_value,
  cast(trunc(now, 'HH24') as timestamp) as time
from fake_time
join table1 on time >= cast(trunc(now, 'HH24') as timestamp) - interval '1' hour
and time < cast(trunc(now, 'HH24') as timestamp)
group by name, now;

NAME     AVG_VALUE TIME                   
------- ---------- -----------------------
QWER1_Z         20 2017-02-10 13:00:00.000
QWER1_V         35 2017-02-10 13:00:00.000
TEST1_Z         15 2017-02-10 13:00:00.000
TEST1_V         10 2017-02-10 13:00:00.000

为了选择您想要的行,我将假时间设为 13:00 而不是 12:00。您显示的 TEST1_V 的平均值也是错误的。

下一阶段,它将把这些转换成你想要的格式,作为一行。为此,您可以将根(即 TEST1QWER1)和字母(Z 或 V)添加为结果集中的额外列,然后将其用作 [=32= 的子查询] - 这需要 11g 或更高:

with fake_time(now) as (
  select timestamp '2017-02-10 13:01:07' from dual
)
select z_name, z_value, v_name, v_value, time
from (
  select substr(name, 1, length(name) - 2) as root,
    substr(name, -1) as zv,
    name,
    avg(value) as avg_value,
    cast(trunc(now, 'HH24') as timestamp) as time
  from fake_time
  join table1 on time >= cast(trunc(now, 'HH24') as timestamp) - interval '1' hour
  and time < cast(trunc(now, 'HH24') as timestamp)
  group by substr(name, 1, length(name) - 2), name, now
)
pivot (max(name) as name, max(avg_value) as value for (zv) in ('Z' as z, 'V' as v));

Z_NAME     Z_VALUE V_NAME     V_VALUE TIME                   
------- ---------- ------- ---------- -----------------------
TEST1_Z         15 TEST1_V         10 2017-02-10 13:00:00.000
QWER1_Z         20 QWER1_V         35 2017-02-10 13:00:00.000

可能还需要一个步骤;在您的示例输出中,您包含了一个原始值的列表,这些值是平均的,但没有确认您是否真的想要这些值,或者它们是否只是为了显示平均值是如何计算的,以帮助我们理解您需要做什么。如果你真的想要包括你可以使用 listagg() 和连接在旋转之前构建 'average' 字符串:

    'avg(' || listagg(value, ',') within group (order by value) || ') = ' || avg(value)
      as avg_value,

得到

Z_NAME  Z_VALUE              V_NAME  V_VALUE              TIME                   
------- -------------------- ------- -------------------- -----------------------
TEST1_Z avg(10,20) = 15      TEST1_V avg(10) = 10         2017-02-10 13:00:00.000
QWER1_Z avg(20) = 20         QWER1_V avg(30,40) = 35      2017-02-10 13:00:00.000

正如我之前所说,我只使用 fake_date CTE 来获取与您的样本数据相匹配的日期。您的真实查询将更像是:

select z_name, z_value, v_name, v_value, time
from (
  select substr(name, 1, length(name) - 2) as root,
    substr(name, -1) as zv,
    name,
    avg(value) as avg_value,
    cast(trunc(sysdate, 'HH24') as timestamp) as time
  from table1
  where time >= cast(trunc(sysdate, 'HH24') as timestamp) - interval '1' hour
  and time < cast(trunc(sysdate, 'HH24') as timestamp)
  group by substr(name, 1, length(name) - 2), name
)
pivot (max(name) as name, max(avg_value) as value for (zv) in ('Z' as z, 'V' as v));