问题
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