我正在尝试使用Oracle 11g(在开发中为11.1,在生产中为11.2)进行数值分析,特别是在具有三列感兴趣的表的表上进行线性插值:时间戳,设备ID和值。
值列保存来自设备的数据(标识为deviceid),该数据是在时间戳记中指定的时间获取的。例如,这是伪数据,但是它给出了这样的想法:
time | deviceid | value ----------------|------------|----------- 01:00:00.000 | 001 | 1.000 01:00:01.000 | 001 | 1.030 01:00:02.000 | 001 | 1.063 01:00:00.050 | 002 | 553.10 01:00:01.355 | 002 | 552.30 01:00:02.155 | 002 | 552.43
来自设备001的时间戳与设备002的时间戳不匹配,但是我需要将来自设备001和002的值放在一行中,并带有一个时间戳,与设备001的时间戳匹配。我要结束的是像这样的东西:
time | device 001 | device 002 ----------------|--------------|------------ 01:00:00.000 | 1.000 | null 01:00:01.000 | 1.030 | 552.520 01:00:02.000 | 1.063 | 552.405
其中,基于在设备001的每个时间戳的任一侧的两个最接近的时间戳处收集的设备002的值对设备002的值进行线性插值。之所以会出现空值,是因为我在设备001的任一侧都没有两个时间戳01:00:00.000,我不想外推该值。
据我了解,我可以使用percentile_cont来执行此操作,但是我不理解我在网上看到的示例。例如,percentile_cont使用的百分位数从何而来?
在此先感谢您的帮助!
我不确定您将如何PERCENTILE_CONT执行所需的插值,但是借助其他分析功能,您可以实现所需的插值。
PERCENTILE_CONT
首先,我们将创建以下函数,该函数将INTERVAL DAY TO SECOND值转换为秒:
INTERVAL DAY TO SECOND
CREATE OR REPLACE FUNCTION intvl_to_seconds( p_interval INTERVAL DAY TO SECOND ) RETURN NUMBER DETERMINISTIC AS BEGIN RETURN EXTRACT(DAY FROM p_interval) * 24*60*60 + EXTRACT(HOUR FROM p_interval) * 60*60 + EXTRACT(MINUTE FROM p_interval) * 60 + EXTRACT(SECOND FROM p_interval); END; /
通过此功能,我们可以使用如下查询:
SELECT d1.time, d1.value AS value1, q2.prev_value + intvl_to_seconds(d1.time - q2.prev_time) * (q2.next_value - q2.prev_value)/intvl_to_seconds(q2.next_time - q2.prev_time) AS value2 FROM devices d1 LEFT OUTER JOIN (SELECT d2.time AS prev_time, d2.value AS prev_value, LEAD(d2.time, 1) OVER (ORDER BY d2.time) AS next_time, LEAD(d2.value, 1) OVER (ORDER BY d2.time) AS next_value FROM devices d2 WHERE d2.deviceid = 2) q2 ON d1.time BETWEEN q2.prev_time AND q2.next_time WHERE d1.deviceid = 1;
我在上面获取了您的数据,将时间戳记的日期部分设置为今天,当我运行上面的查询时,得到了以下结果:
TO_CHAR(D1.TIME)VALUE1 VALUE2 ------------------------------------- ---------- --- ------- 2011年9月9日01.00.00.000000 1 2011年9月9日01.00.01.000000 1.03 552.517625 2011年9月9日01.00.02.000000 1.063 552.404813
(我添加了一个TO_CHAR环绕d1.time以减少SQL * Plus中过多的间距。)
TO_CHAR
d1.time
如果您使用DATEs而不是TIMESTAMPs,则不需要此函数:您可以减去日期。
DATE
TIMESTAMP