小编典典

如何使用Oracle SQL执行线性插值?

sql

我正在尝试使用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使用的百分位数从何而来?

在此先感谢您的帮助!


阅读 246

收藏
2021-04-28

共1个答案

小编典典

我不确定您将如何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
------------------------------------- ---------- --- -------
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中过多的间距。)

如果您使用DATEs而不是TIMESTAMPs,则不需要此函数:您可以减去日期。

2021-04-28