Как я могу выполнить линейную интерполяцию с использованием оракула SQL? - PullRequest
3 голосов
/ 09 сентября 2011

Я пытаюсь использовать Oracle 11g (11.1 в dev, 11.2 в производстве) для числового анализа, в частности, линейной интерполяции для таблицы, которая имеет три интересующих столбца: метку времени, идентификатор устройства и значение.

Столбцы значений содержат данные с устройства (с идентификатором 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 было линейно интерполировано на основе значений для устройства 002, собранных на двух ближайших временных отметках с обеих сторон каждой временной отметки для устройства 001. Ноль возникает из-за того, что у меня нет двух временных меток для устройства 002 по обе стороны от 01: 00: 00.000, и я не хочу экстраполировать значение.

Из того, что я понимаю, я могу использовать процентное соединение для этого, но я не понимаю примеров, которые я видел в Интернете. Например, откуда взялся бы процентиль, используемый процентилем_контом?

Заранее спасибо за помощь!

Ответы [ 3 ]

3 голосов
/ 10 сентября 2011

Я не уверен, как бы вы использовали 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.000000                      1
09-SEP-11 01.00.01.000000                   1.03 552.517625
09-SEP-11 01.00.02.000000                  1.063 552.404813

(я добавил TO_CHAR около d1.time, чтобы сократить чрезмерный интервал в SQL * Plus.)

Если вы используете DATE с вместо TIMESTAMP с, функция вам не нужна: вы можете просто вычесть даты.

0 голосов
/ 19 октября 2011

Окончательное решение с диапазоном дат:

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';
0 голосов
/ 16 сентября 2011

Я использую модифицированную версию запроса @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, возможно, поэтому обычное объединение теряет внешние данные.

Я не получаю нулевые значения для интерполированных данных, если использую обычное соединение, но при использовании обычного соединения я теряю данные для устройства 1 за пределами конечных точек для устройства 2 (интерполированное устройство в q2). Предложения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...