Заполнение нулей со средним значением между соседями с ограничением на другой столбец - PullRequest
0 голосов
/ 30 марта 2019

У меня есть таблица с именами столбцов "id", "time", "value" и когда «значение» равно нулю, я хочу, чтобы оно было средним между ближайшими соседями по столбцу «время» для этого идентификатора

Моя проблема в точности описана здесь выберите ближайших соседей , но ответ не объясняет, как я могу найти ближайших соседей с ограничением на другой столбец (идентификатор должен быть таким же)

Пример: во втором ряду "значение" отсутствует

id       | time  | value
-------------------------
11111    | 1     | 5.0
11111    | 10    | 
22222    | 7     | 32.6
33333    | 11    | 15.88
11111    | 15    | 20.0

и я хочу, чтобы это было:

id       | time  | value
-------------------------
11111    | 1     | 5.0
11111    | 10    | 12.5*
22222    | 7     | 32.6
33333    | 11    | 15.88
11111    | 15    | 20.0

как (20,0 + 5,0) / 2 = 12,5

Как его можно получить в MySQL?

Ответы [ 3 ]

0 голосов
/ 30 марта 2019

просто присоединяйся к себе, но будь осторожен: NEXT_VALUE

SELECT ID_,
   TIME_,
   CASE
      WHEN VALUE_ IS NULL THEN (LAST_VALUE + NEXT_VALUE) / 2
      ELSE VALUE_
   END AS REAL_VALUE
FROM (SELECT ROW_NUMBER () OVER (PARTITION BY ID_ ORDER BY TIME_ DESC)
              NOW_ROW_NUM,
           ID_,
           TIME_,
           VALUE_
      FROM TESTTABLE)
   LEFT JOIN (SELECT (ROW_NUMBER ()
                         OVER (PARTITION BY ID_ ORDER BY TIME_ DESC))
                     - 1
                        LAST_ROW_NUM,
                     ID_ AS LAST_ID,
                     VALUE_ AS LAST_VALUE
                FROM TESTTABLE)
      ON ID_ = LAST_ID AND NOW_ROW_NUM = LAST_ROW_NUM
   LEFT JOIN (SELECT (ROW_NUMBER ()
                         OVER (PARTITION BY ID_ ORDER BY TIME_ DESC))
                     + 1
                        NEXT_ROW_NUM,
                     ID_ AS NEXT_ID,
                     VALUE_ AS NEXT_VALUE
                FROM TESTTABLE)
      ON ID_ = LAST_ID AND NOW_ROW_NUM = NEXT_ROW_NUM
0 голосов
/ 31 марта 2019

Просто используйте lead() и lag().Самый простой ответ:

selet t.*
      (case when value is null
            then ( lag(value) over (partition by id order by time) + lead(value) over (partition by id order by time) ) / 2
            else value
       end) as new_value
from t;

Это не работает для первого или последнего значения.Вместо этого вы можете использовать:

selet t.*
      (case when value is null
            then ( avg(value) over (partition by id order by time rows between 1 preceding and 1 following)
            else value
       end) as new_value
from t;

Это вычисляет среднее значение на основе доступных данных в предыдущих и последующих строках.

0 голосов
/ 30 марта 2019

Предполагая, что time определяет порядок и является уникальным (для этого необходим уникальный столбец и столбец, который определяет порядок), один из методов заключается в использовании подзапросов, получающих верхнюю (нижнюю) value записей сменьше (больше) time с использованием ORDER BY и LIMIT.

SELECT t1.id,
       t1.time,
       coalesce(t1.value,
                ((SELECT t2.value
                         FROM elbat t2
                         WHERE t2.id = t1.id
                               AND t2.time < t1.time
                         ORDER BY t2.time DESC
                         LIMIT 1)
                 +
                 (SELECT t2.value
                         FROM elbat t2
                         WHERE t2.id = t1.id
                               AND t2.time > t1.time
                         ORDER BY t2.time ASC
                         LIMIT 1)
                )
                /
                2) value
       FROM elbat t1;

db <> fiddle

Но это может заполнить пробелы только шириной в одну строку,Если могут быть большие промежутки, вам нужно будет определить, каковы следующие ненулевые соседи этих строк.

...