当我在下面选择时运行:
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(值)显示为一行,但显示为两栏
以下是在下午12点00分运行查询时所需结果的示例:
答案 0 :(得分:1)
你要求三件事,可以认为是三个步骤。获取时间窗口非常简单,只是稍微复杂一点,因为您的列是时间戳而不是日期。你暗示这将在一小时内运行,但它可能会稍微后续 - 可能是一两秒钟? - 考虑到这一点可能更安全。您可以使用the trunc()
function将日期值修改为所需的精度,因此仅查看当前小时您将截断为HH [24]。然后,您可以cast返回时间戳。您可以使用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()
将日期时间值的最终格式设置为字符串)。
请注意,截断的结果现在是一个日期(该输出中的A),因此我将其转换回时间戳(B)。您想要的范围基本上是time >= A and time < B
。您可以使用sysdate
代替systimestamp
作为trunc()
的输入。
对于使用systimestamp
或sysdate
的示例数据,我找不到任何内容,因此我会在其余部分使用假的固定时间,在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
显示的平均值也是错误的。
下一阶段将它们转换为您想要的格式,作为单行。为此,您可以将根(即TEST1
或QWER1
)和字母(Z或V)添加为结果集中的额外列,然后将其用作{{3}的子查询} - 这需要11克或更高:
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()
和连接来构建“平均值”&#39;旋转前的字符串:
'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));
答案 1 :(得分:0)
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