【发布时间】:2013-11-08 19:00:41
【问题描述】:
假设我有一个这样的数据集(在 Oracle 11g 数据库环境中)
CHANGE_DATE VALUE
------------------ ----------
03-NOV-13 06.56.01 3027.97
03-NOV-13 06.57.01 3030.59
03-NOV-13 06.58.01 3032.33
03-NOV-13 06.59.01 3047.41
03-NOV-13 07.00.02 3045.82
03-NOV-13 07.01.01 3046.63
03-NOV-13 07.02.01 3020.29
03-NOV-13 07.03.02 3019.38
03-NOV-13 07.04.01 3020.76
03-NOV-13 07.05.01 3008.53
我感兴趣的是一个 select 语句,它只显示足够大的变化的值,例如0.1%。在上述数据集中,所需的输出将是
03-NOV-13 06.56.01 3027.97
03-NOV-13 06.58.01 3032.33
03-NOV-13 06.59.01 3047.41
03-NOV-13 07.04.01 3020.29
03-NOV-13 07.05.01 3008.53
编辑:解释目的:第一行是第一个参考值。任何后续行值都应与此进行比较。如果相对于参考值的变化不超过 x%,请继续。如果值确实超过阈值,请选择此行并保留此新值作为参考以比较下一行。
如果我只是按照此处讨论的内容在整数值之间翻转,我知道如何实现这样的事情:Select rows where column value has changed
我尝试使用以下方法实现一些东西:
with t as (
select to_date('03-NOV-13 06.56.01','dd/mm/yyyy hh24:mi:ss') change_date, 3027.97 value from dual union all
select to_date('03-NOV-13 06.57.01','dd/mm/yyyy hh24:mi:ss'), 3030.59 from dual union all
select to_date('03-NOV-13 06.58.01','dd/mm/yyyy hh24:mi:ss'), 3032.33 from dual union all
select to_date('03-NOV-13 06.59.01','dd/mm/yyyy hh24:mi:ss'), 3047.41 from dual union all
select to_date('03-NOV-13 07.00.02','dd/mm/yyyy hh24:mi:ss'), 3045.82 from dual union all
select to_date('03-NOV-13 07.01.01','dd/mm/yyyy hh24:mi:ss'), 3046.63 from dual union all
select to_date('03-NOV-13 07.02.01','dd/mm/yyyy hh24:mi:ss'), 3020.29 from dual union all
select to_date('03-NOV-13 07.03.02','dd/mm/yyyy hh24:mi:ss'), 3019.38 from dual union all
select to_date('03-NOV-13 07.04.01','dd/mm/yyyy hh24:mi:ss'), 3020.76 from dual union all
select to_date('03-NOV-13 07.05.01','dd/mm/yyyy hh24:mi:ss'), 3008.53 from dual )
, x as ( select value, ROUND(value,-1) round_value, change_date, ROW_NUMBER() OVER (ORDER BY change_date) as rn from t order by change_date) select x.value, x.change_date from x join x y on x.rn = y.rn+1 and x.round_value <> y.round_value;
这给了
3047.41 03-NOV-13
3020.29 03-NOV-13
3008.53 03-NOV-13
这不是太离谱,但总是只与前一个值而不是第一个未抑制的值进行比较。显然,这只是进行了四舍五入,并不寻找任何百分比变化。
我也尝试过这样玩延迟
with t as (
select to_date('03-NOV-13 06.56.01','dd/mm/yyyy hh24:mi:ss') change_date, 3027.97 value from dual union all
select to_date('03-NOV-13 06.57.01','dd/mm/yyyy hh24:mi:ss'), 3030.59 from dual union all
select to_date('03-NOV-13 06.58.01','dd/mm/yyyy hh24:mi:ss'), 3032.33 from dual union all
select to_date('03-NOV-13 06.59.01','dd/mm/yyyy hh24:mi:ss'), 3047.41 from dual union all
select to_date('03-NOV-13 07.00.02','dd/mm/yyyy hh24:mi:ss'), 3045.82 from dual union all
select to_date('03-NOV-13 07.01.01','dd/mm/yyyy hh24:mi:ss'), 3046.63 from dual union all
select to_date('03-NOV-13 07.02.01','dd/mm/yyyy hh24:mi:ss'), 3020.29 from dual union all
select to_date('03-NOV-13 07.03.02','dd/mm/yyyy hh24:mi:ss'), 3019.38 from dual union all
select to_date('03-NOV-13 07.04.01','dd/mm/yyyy hh24:mi:ss'), 3020.76 from dual union all
select to_date('03-NOV-13 07.05.01','dd/mm/yyyy hh24:mi:ss'), 3008.53 from dual )
select value, change_date, case when abs( lag(value,1,0) over(order by change_date) - value ) / value > 0.001 then value else lag(value,1,0) over(order by change_date) end start_of_group from t;
导致
VALUE CHANGE_DA START_OF_GROUP
---------- --------- --------------
3027.97 03-NOV-13 3027.97
3030.59 03-NOV-13 3027.97
3032.33 03-NOV-13 3030.59
3047.41 03-NOV-13 3047.41
3045.82 03-NOV-13 3047.41
3046.63 03-NOV-13 3045.82
3020.29 03-NOV-13 3020.29
3019.38 03-NOV-13 3020.29
3020.76 03-NOV-13 3019.38
3008.53 03-NOV-13 3008.53
这似乎也是朝着正确方向迈出的一步,但存在同样的问题,即不是对“start_of_group”列而是对“value”列进行比较
我将不胜感激有关如何实现这一目标的任何提示。请让我知道问题是否足够清楚,或者我是否应该添加任何信息。
附:第一次发帖,希望我设法以有意义的方式发布问题
【问题讨论】:
-
嗨,欢迎来到 Stack Overflow!你的问题很好。请仅澄清一点:“足够大的变化”是什么意思?高于和/或低于平均值 0.1% 以上?以前的值?最后 N 条记录的滚动平均值?过去一小时内记录的滚动平均值?
-
@DaniloPiazzalunga,我试图在所需的输出下方澄清。