Replacing NULL value in current row based on 'closest' matching 'earlier' row. (date based table)

∥☆過路亽.° 提交于 2020-01-15 08:17:24

问题


I have the following mysql table

+---------------------+------+
| 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 |
+---------------------+------+

I want to create an algorithm (in PHP) that fill the NULL values based on the last non-null value. So the table will become the following

+---------------------+------+
| 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 |
+---------------------+------+

I'm looking for clues on how to approach this situation. I'm using PHP-Laravel.

There is an SQLFiddle here for 'standard' SQL.


回答1:


As comments indicate, you should be fixing this when you populate the table. That said, it can be done in PHP or MySQL. Here is one option:

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

Bear in mind that your result will change depending on ordering and WHERE and so on. Use SET @x:=0; to define your default value for cases when first row has NULL value.

If you need to fix the data permanently, rather than for single query, you can update the table with 'correct' values:

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



回答2:


If you want to use just SQL, you could use this UPDATE query:

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

Please see a fiddle here.

The subquery will return, for every NULL row the previous date with a non-NULL value. Then I'm joining the table with itself to get the value and to update the null row.



来源:https://stackoverflow.com/questions/32541798/replacing-null-value-in-current-row-based-on-closest-matching-earlier-row

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!