Home > Back-end >  How to chose the previous non null value in a column for null values resulting from an outer join
How to chose the previous non null value in a column for null values resulting from an outer join

Time:07-18

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;
  • Related