12

I have a table bank_accounts:

    Column     |         Type          |                                Modifiers                                | Storage  | Stats target | Description 
---------------+-----------------------+-------------------------------------------------------------------------+----------+--------------+-------------
 id            | integer               | not null default nextval('bank_accounts_id_seq'::regclass)              | plain    |              | 
 name          | character varying(50) |                                                                         | extended |              | 
 bank_accounts | jsonb                 | not null                                                                | extended |              | 

And it has some JSON in the jsonb column:

 id | name  |                              bank_accounts                               
----+-------+--------------------------------------------------------------------------
  1 | test1 | [{"name": "acct1", "balance": -500}, {"name": "acct2", "balance": -300}]

And I am using jsonb_array_elements to get a list of the accounts for one user:

select jsonb_array_elements(bank_accounts)->>'name' as name, jsonb_array_elements(bank_accounts)->>'balance' as balance from bank_accounts;
 name  | balance 
-------+---------
 acct1 | -500
 acct2 | -300

That's all great. But how do I get each row to have a unique id? I'd like to map each row to a hibernate object, but I'm having trouble doing that because I can't find a way to get each row to have a unique id.

1 Answer 1

13

Try a different, clean approach with JOIN LATERAL:

SELECT b.id, t.rn
     , t.account->>'name' AS name
     , t.account->>'balance' AS balance
FROM   bank_accounts b
LEFT   JOIN LATERAL jsonb_array_elements(b.bank_accounts)
                    WITH ORDINALITY AS t (account, rn) ON true;

If you don't care for rows with empty or null values in bank_accounts, use a simpler CROSS JOIN:

SELECT ...
FROM   bank_accounts b
     , jsonb_array_elements(b.bank_accounts) WITH ORDINALITY AS t (account, rn);

The key ingredient is WITH ORDINALITY to produce row numbers for set-returning functions on the fly. It was introduced with Postgres 9.4 - just like jsonb.

rn is unique per underlying row in bank_accounts.
To be unique across the whole result set, combine it with b.id.

About WITH ORDINALITY:

Related:

1
  • Fantastic! Thank you very much. Yes, that works perfectly. I need to wrap my head round join lateral and with ordinality.. Commented Apr 13, 2015 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.