我如何使用oracle SQL执行线性插值



我正在尝试使用Oracle 11g(开发11.1,生产11.2)进行数值分析,特别是对一个有三列感兴趣的表进行线性插值:时间戳,设备id和值。

值列保存来自设备(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

其中设备002的值是基于在设备001的每个时间戳两侧的两个最接近的时间戳上收集的设备002的值线性插值的。出现空值是因为我在01:00:00.000的两侧没有设备002的两个时间戳,并且我不想推断该值。

据我所知,我可以使用percentile_cont来做到这一点,但我不明白我在网上看到的例子。例如,percentile_cont使用的百分位数来自哪里?

提前感谢您的帮助!

我不确定你如何使用PERCENTILE_CONT来做你要求的插值,但在不同分析函数的帮助下,你可以实现你想要的。

首先,我们将创建以下函数,将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------------------------------------- ---------- ----------09-sep-11 01.00.00.00000009-sep-11 01.00.01.000000 1.03 552.51762509-sep-11 01.00.02.000000 1.063 552.404813之前

(我在d1.time周围添加了TO_CHAR,以减少SQL*Plus中的过多间距)

如果你使用DATE s而不是TIMESTAMP s,你不需要这个函数:你可以只减去日期。

我使用的是@Luke Woodward的查询的修改版本:

SELECT d1.time,
   d1.value AS value1,
   q2.prev_value + 
   (EXTRACT( SECOND FROM (d1.time - q2.prev_time)) +
    EXTRACT( MINUTE FROM (d1.time - q2.prev_time)) * 60 ) 
    * (q2.next_value - q2.prev_value)/
      (EXTRACT ( SECOND FROM (q2.next_time - q2.prev_time)) + 
      EXTRACT ( MINUTE FROM (q2.next_time - q2.prev_time)) * 60)  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
                      and time between '20100914 000000' and '20100915 000000'
                ) q2
           ON d1.time BETWEEN q2.prev_time AND q2.next_time
 WHERE d1.deviceid = 1;

但是插入的值总是显示为空,即使在日期范围内有设备2的数据。

注意,我必须在q2中为查询添加一个日期范围,这可能是正常连接丢失外部数据的原因。

如果我使用正常连接,我不会得到插入数据的空值,但在使用正常连接时,我会在设备2 (q2中的插入设备)的端点之外丢失设备1的数据。建议吗?

日期范围的最终解决方案:

SELECT
    d1.time,
    d1.value AS value1,
    q2.prev_value + 
    (EXTRACT( SECOND FROM (d1.time - q2.prev_time)) +
     EXTRACT( MINUTE FROM (d1.time - q2.prev_time)) * 60 ) 
     * (q2.next_value - q2.prev_value)/
       (EXTRACT ( SECOND FROM (q2.next_time - q2.prev_time)) + 
        EXTRACT ( MINUTE FROM (q2.next_time - q2.prev_time)) * 60
    )  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
    AND time BETWEEN '20100914 000000' AND '20100915 000000'
) q2
ON d1.time BETWEEN q2.prev_time AND q2.next_time
WHERE d1.deviceid = 1
AND time BETWEEN '20100914 000000' AND '20100915 000000';

相关内容

  • 没有找到相关文章

最新更新