with recursive r (key, j1) as ( select null :: text, '[ 1, 2, 3, { "f1": 1, "f2": [5, 6] }, 4 ]' :: json-- ↑ arbitrary JSON unionall -- not only union select k, j2 from r, json_typeof(j1) as t, cast(case when t = 'object' then json_object_keys(j1) end as text) as k, cast(case when k is not null then json_extract_path(j1, k) when t = 'array' then json_array_elements(j1) end as json) as j2 where j2 is not null ) select * from r; +-----+-------------------------------------------+ | key | j1 | +-----+-------------------------------------------+ | | [ 1, 2, 3, { "f1": 1, "f2": [5, 6] }, 4 ] | | | 1 | | | 2 | | | 3 | | | { "f1": 1, "f2": [5, 6] } | | | 4 | | f1 | 1 | | f2 | [5, 6] | | | 5 | | | 6 | +-----+-------------------------------------------+ (10 rows)

with recursive r (key, j1) as ( select null :: text, ' { "f2": { "f3": 1 }, "f4": { "f5": 99, "f6": "foo" } } ' :: jsonb-- ↑ arbitrary JSONB union select k, j2 from r, jsonb_typeof(j1) as t, cast(case when t = 'object' then jsonb_object_keys(j1) end as text) as k, cast(case when k is not null then jsonb_extract_path(j1, k) when t = 'array' then jsonb_array_elements(j1) end as jsonb) as j2 where j2 is not null ) select * from r; +-----+--------------------------------------------------+ | key | j1 | +-----+--------------------------------------------------+ | | {"f2": {"f3": 1}, "f4": {"f5": 99, "f6": "foo"}} | | f2 | {"f3": 1} | | f4 | {"f5": 99, "f6": "foo"} | | f3 | 1 | | f5 | 99 | | f6 | "foo" | +-----+--------------------------------------------------+ (6 rows)

使ってる関数は下記四つ、いずれも
• json(b)_typeof
• json(b)_object_keys
• json(b)_extract_path
• json(b)_array_elements
JSON
WITH RECURSIVE
アンカンファレンスでデモした、もっと複雑な