Scalar function processes a value and it can nullify it, but a set-returning function generates values, so it can end up not generating one at all. As already suggested, you can use the scalar function
SELECT id, jsonb_path_query_first(data::jsonb, '$[*]?(@.key=="2").value')
FROM example;
Alternatively, you can keep the SRF, Set-Returning Function jsonb_path_query()
→ setof jsonb
by wrapping it in a scalar subquery or replacing its implicit inner join. Both will indicate lack of generated values with a null, but the latter can also still spawn and return multiple: demo
SELECT id,(SELECT jsonb_path_query(data::jsonb,'$[*]?(@.key=="2").value')LIMIT 1)
FROM example;
SELECT id, values
FROM example LEFT JOIN jsonb_path_query(data::jsonb, '$[*]?(@.key=="2").value')
AS srf(values)
ON true;
Row 2 wasn't generating any rows in that function, which is why you didn't see it - there was no row to have a null
in. Select section is not a normal place for an SRF - when applied there, it ends up pushed down to from
section to be inner joined
with. And inner join
with an empty set, is an empty set. That, combined with implicit join behaviour, is why you can read:
SELECT srf();
as an actual SELECT b.x FROM srf() AS b(x);
SELECT a.id, srf() FROM a;
meaning SELECT a.id, b.x FROM a, srf() AS b(x);
SELECT a.id, b.x FROM a, srf(a.v) AS b(x);
and SELECT a.id, srf(a.v) FROM a;
actually meaning:
SELECT a.id, b.x FROM a INNER JOIN srf(a.v) AS b(x) ON true;
This INNER JOIN
threw out your id
s that didn't have result-generating data
. LEFT JOIN
won't.
Another illustration with a more obvious generate_series()
"give me this many rows" SRF: demo
create table table1(id smallserial, how_many_to_generate int);
insert into table1(how_many_to_generate) values (1),(0),(2),(0),(1);
--no rows for the 2nd and 4th entry where `how_many_to_generate` is 0
--on the other hand, the 3rd entry requested and received two rows
select id, how_many_to_generate, generate_series(1, how_many_to_generate)
from table1;
-- id | how_many_to_generate | generate_series
------+----------------------+-----------------
-- 1 | 1 | 1
-- 3 | 2 | 1
-- 3 | 2 | 2
-- 5 | 1 | 1
jsonb
? Then you can also get rid of the casting.jsonb
is the recommended data type for JSON values anyway. – Actium