Search code examples
sqlpostgresqljsonb

PostgreSQL: fill records using fields from JSONB with jsonb_to_record()


I have a function returning jsonb

SELECT get_my_records( 'some', 'args' );
get_my_records
{ "a": 1, "b": 3.14 }
{ "a": 2, "b": 2.71 }
...

and trying to use jsonb_to_record() to convert the records to

a b
1 3.14
2 2.71
... ...

Tried

SELECT * 
FROM jsonb_to_record( val ) as x( a int, b double precision ) 
FROM get_my_records( 'some', 'arg' ) AS val;`

and a few variations but without success. How does one go about it?

(probably lacking proper terminology to get meaningful results from the web search)


Solution

  • Your attempt was mostly correct, but you added multiple FROM lists for some reason, which isn't allowed. You can get away with a single FROM item if you use ->> accessors instead: demo

    select (j->>'a')::int as a, 
           (j->>'b')::double precision as b 
    from get_my_records( 'some', 'args' ) as jdata(j);
    
    a b
    1 3.14
    2 2.71

    You can't have multiple from lists in a single query - you'd have to split that into CTEs/subqueries

    SELECT * 
    FROM jsonb_to_record( val ) as x( a int, b double precision ) 
    FROM get_my_records( 'some', 'arg' ) AS val;
    
    ERROR:  syntax error at or near "FROM"
    LINE 4: FROM get_my_records( 'some', 'arg' ) AS val;
            ^
    

    Or, you can just extend your from list by joining the sources:

    SELECT x.* 
    FROM get_my_records( 'some', 'arg' ) AS val 
    LEFT JOIN LATERAL jsonb_to_record(val) as x(a int,b double precision) ON TRUE;
    
    a b
    1 3.14
    2 2.71

    You can use a comma , to join implicitly, since lateral is implied by dependence between these set-returning functions posing as sources, and on true just lets them join freely.

    SELECT x.* 
    FROM get_my_records( 'some', 'arg' ) AS val,
         jsonb_to_record( val ) as x( a int, b double precision );