Замена значения NULL в текущей строке на основе «ближайшего» соответствия «ранее». (таблица, основанная на дате)

У меня есть следующая таблица mysql

+---------------------+------+ | time | val | +---------------------+------+ | 2005-02-03 00:00:00 | 2.11 | | 2005-02-04 00:00:00 | 2.11 | | 2005-02-05 00:00:00 | NULL | | 2005-02-06 00:00:00 | NULL | | 2005-02-07 00:00:00 | 3.43 | | 2005-02-08 00:00:00 | NULL | | 2005-02-09 00:00:00 | NULL | | 2005-02-10 00:00:00 | 5.66 | | 2005-02-11 00:00:00 | 5.66 | | 2005-02-12 00:00:00 | NULL | +---------------------+------+ 

Я хочу создать алгоритм (в PHP), который заполняет значения NULL на основе последнего ненулевого значения. Таким образом, таблица станет следующей

 +---------------------+------+ | time | val | +---------------------+------+ | 2005-02-03 00:00:00 | 2.11 | | 2005-02-04 00:00:00 | 2.11 | | 2005-02-05 00:00:00 |>2.11 | | 2005-02-06 00:00:00 |>2.11 | | 2005-02-07 00:00:00 | 3.43 | | 2005-02-08 00:00:00 |>3.43 | | 2005-02-09 00:00:00 |>3.43 | | 2005-02-10 00:00:00 | 5.66 | | 2005-02-11 00:00:00 | 5.66 | | 2005-02-12 00:00:00 |>5.66 | +---------------------+------+ 

Я ищу подсказки о том, как подойти к этой ситуации. Я использую PHP-Laravel.

Здесь используется SQLFiddle для стандартного SQL.

Как видно из комментариев, вы должны исправлять это при заполнении таблицы. Тем не менее, это можно сделать в PHP или MySQL. Вот один из вариантов:

 SET @x:=0; SELECT `time`, IF(val IS NOT NULL, @x:=val, @x) AS val FROM yourtable ORDER BY `time`; 

Имейте в виду, что ваш результат изменится в зависимости от порядка и WHERE и так далее. Используйте SET @x:=0; для определения значения по умолчанию для случаев, когда первая строка имеет значение NULL .

Если вам необходимо фиксировать данные на постоянной основе, а не для одного запроса, вы можете обновить таблицу с помощью «правильных» значений:

 SET @x:=0; UPDATE yourtable SET val=IF(val IS NOT NULL, @x:=val, @x) ORDER BY `time`; 

Если вы хотите использовать только SQL, вы можете использовать этот запрос UPDATE:

 UPDATE tab INNER JOIN ( SELECT t1.time, MAX(t2.time) prev_time FROM tab t1 INNER JOIN tab t2 ON t1.time>t2.time WHERE t1.val IS NULL AND t2.val IS NOT NULL GROUP BY t1.time ) p ON tab.time = p.time INNER JOIN tab t2 ON p.prev_time = t2.time SET tab.val = t2.val 

Пожалуйста, см. Скрипку здесь .

Подзапрос вернет для каждой строки NULL предыдущую дату с не-NULL значением. Затем я присоединяюсь к таблице с собой, чтобы получить значение и обновить нулевую строку.