Say I have a table A, which has null values in a particular column say Value as a result of an outer join. Now if A represents a value such as cumsum, it doesnt make sense for it to drop to null in the middle
| ID | Value |
| --- | ----- |
| 1 | null |
| 2 | 576 |
| 3 | null |
| 4 | 695 |
| 5 | null |
so is it possible to transform the table A, to table B which might look like this
| ID | Value |
| --- | ----- |
| 1 | 0 |
| 2 | 576 |
| 3 | 576 |
| 4 | 695 |
| 5 | 695 |
Therefore is it possible to replace the null values in a column with either the previous non null value, or if in case that is not available a default value 0. This transformation also has to be done across all columns in a table, with 10 or so columns.
CodePudding user response:
Should be compatible with general SQL, definitely works on postgreSQL:
SELECT a1.id, COALESCE(a2.value, 0) FROM
(
SELECT a1.id AS id, MAX(a2.id) as idref FROM a a1 LEFT JOIN a a2
ON a2.id <= a1.id AND a2.value IS NOT NULL GROUP BY a1.id
) AS a1
LEFT JOIN a a2 ON a2.id = a1.idref
Double join required – doesn't appear optimal to me, but at least works.
Concerning your comment: The pattern could be extended, but you'd need to add yet another two joins for each further column if the respective existing values might come from different rows.
Edit:
While still requiring two sub-queries (instead of joins), this variant seems to perform slightly better on postgre SQL:
SELECT
a1.id,
COALESCE
(
(
SELECT a2.value FROM a a2 WHERE a2.id =
(SELECT MAX(a3.id) FROM a a3 WHERE a3.id <= a1.id AND a3.value IS NOT NULL)
),
0
)
FROM a a1
You'll still need a set of two sub-queries for every additional column (unless all data comes can be retrieved from the same row), though performance gain likely will accumulate then.
CodePudding user response:
WITH cte AS (
SELECT
id,
value,
count(value) OVER (ORDER BY id)
FROM (
VALUES (1, NULL),
(2, 576),
(3, NULL),
(4, 695),
(5, NULL),
(6, NULL)) g (id, value) ORDER BY id
)
SELECT
id,
value,
coalesce(first_value(value) OVER (PARTITION BY count ORDER BY id), 0)
FROM
cte
ORDER BY
id;