Original answer
This works up to Postgres 9.6. The behavior of set-returning functions in the SELECT
list was changed (sanitized) in Postgres 10. See below!
Upon revisiting this question it struck me that this can be simpler and faster.
Reverse the logic of the currently accepted solution by @a_horse:
SELECT id, CASE WHEN values <> '{}' THEN unnest(values) END AS value
FROM tbl;
fiddle
This returns a row with NULL
in value
for an empty array as well as for a NULL
array, because only an array with elements in it produces TRUE
in the test values <> '{}'
.
Works for arrays of any type, since the literal '{}' is automatically coerced to a matching type.
Without explicit ELSE
branch, CASE
returns NULL
, which is what we want anyway.
Arrays with a NULL
elements will return rows regardless.
However. I found an anomaly and posted a question concerning that:
Turned out to be a bug that was fixed after my report for pg 9.3+.
Since Postgres 10
The short syntax above stops working after the behavior of set-returning functions in the SELECT
list has been reworked (sanitized). See:
A LATERAL
subquery is the clean, versatile solution, and works since Postgres 9.3, where LATERAL
was added:
SELECT t.id, v.value
FROM tbl t
LEFT JOIN LATERAL unnest(t.values) AS v(value) ON true;
Or, with minimal syntax:
SELECT id, value
FROM tbl
LEFT JOIN LATERAL unnest(values) value ON true;
fiddle
See: