将 JSONB 数组转换为列

Convert JSONB Array to Columns

我有一个查询 returns 包含 jsonb 对象的单个列。以下是一些返回行的示例(jsonb::text 以确保易读性):

[{"amount": 3, "consumable": "Mitsu 90mm ODEX Pilot Bit", "consumed_date": "2017-02-17"}]
[{"amount": 3, "consumable": "BOP Rubber", "consumed_date": "2017-02-17"}]
[{"amount": 13, "consumable": "NWJ Long Saver Sub Pin x Box", "consumed_date": "2017-02-18"}, 
    {"amount": 70, "consumable": "NWJ Long Saver Sub Pin x Box", "consumed_date": "2017-02-17"}]
[{"amount": 63, "consumable": "Methyl Hydrate - Per Litre", "consumed_date": "2017-02-17"}]
[{"amount": 6, "consumable": "Cyclone Discharge Hose Assembly", "consumed_date": "2017-02-17"}]

给出这些示例数据,我想要一个查询来生成具有架构

的 table
consumable                      | 2017-02-17 | 2017-02-18
`````````````````````````````````````````````````````````
BOP Rubber                      | 3          | NULL
Cyclone Discharge Hose Assembly | 6          | NULL
Methyl Hydrate - Per Litre      | 63         | NULL
Mitsu 90mm ODEX Pilot Bit       | 3          | NULL
NWJ Long Saver Sub Pin x Box    | 70         | 13

无法向此数据库实例添加 tablefunc 扩展。

步骤 1.

您可以在 json 对象中为每个 consumable 汇总金额。 json 有 consumed_dates 作为它们的键:

with test(js) as (
values
    ('[{"amount": 3, "consumable": "Mitsu 90mm ODEX Pilot Bit", "consumed_date": "2017-02-17"}]'::jsonb),
    ('[{"amount": 3, "consumable": "BOP Rubber", "consumed_date": "2017-02-17"}]'),
    ('[{"amount": 13, "consumable": "NWJ Long Saver Sub Pin x Box", "consumed_date": "2017-02-18"}, {"amount": 70, "consumable": "NWJ Long Saver Sub Pin x Box", "consumed_date": "2017-02-17"}]'),
    ('[{"amount": 63, "consumable": "Methyl Hydrate - Per Litre", "consumed_date": "2017-02-17"}]'),
    ('[{"amount": 6, "consumable": "Cyclone Discharge Hose Assembly", "consumed_date": "2017-02-17"}]')
)

select consumable, jsonb_object_agg(consumed_date, amount) as amounts
from (
    select
        e->>'consumable' as consumable,
        (e->>'amount')::int as amount,
        e->>'consumed_date' as consumed_date
    from test,
    lateral jsonb_array_elements(js) e
    ) s
group by 1;

           consumable            |               amounts                
---------------------------------+--------------------------------------
 Mitsu 90mm ODEX Pilot Bit       | {"2017-02-17": 3}
 BOP Rubber                      | {"2017-02-17": 3}
 NWJ Long Saver Sub Pin x Box    | {"2017-02-17": 70, "2017-02-18": 13}
 Methyl Hydrate - Per Litre      | {"2017-02-17": 63}
 Cyclone Discharge Hose Assembly | {"2017-02-17": 6}
(5 rows)

第 2 步

使用 create_jsonb_pivot_view() 描述的函数 。 您必须使用上述数据创建一个新的 table 才能使用该功能,例如:

drop table if exists my_new_table;
create table my_new_table as
    with test(js) as (
    --
    -- the above query
    ---
    group by 1;

select create_jsonb_pivot_view('my_new_table', 'consumable', 'amounts');

select * 
from my_new_table_view
order by 1;

           consumable            | 2017-02-17 | 2017-02-18 
---------------------------------+------------+------------
 BOP Rubber                      | 3          | 
 Cyclone Discharge Hose Assembly | 6          | 
 Methyl Hydrate - Per Litre      | 63         | 
 Mitsu 90mm ODEX Pilot Bit       | 3          | 
 NWJ Long Saver Sub Pin x Box    | 70         | 13
(5 rows)    

备选方案

您可以使用此查询在不使用 DDL 的情况下获得尽可能接近所需格式的结果(假设 the_data 包含问题中的数据):

with aux as (
    select
        e->>'consumable' as consumable,
        e->>'amount' as amount,
        e->>'consumed_date' as consumed_date
    from the_data,
    lateral jsonb_array_elements(js) e
)
select 
    null as consumable, 
    array_agg(distinct consumed_date order by consumed_date) as amounts
from aux
union all
select 
    consumable, 
    array_agg(amount order by consumed_date) as amounts
from (
    select distinct t1.consumed_date, t2.consumable
    from aux t1
    cross join aux t2
    ) s
left join aux t using(consumed_date, consumable)
group by 1
order by 1 nulls first;

           consumable            |         amounts         
---------------------------------+-------------------------
                                 | {2017-02-17,2017-02-18}
 BOP Rubber                      | {3,NULL}
 Cyclone Discharge Hose Assembly | {6,NULL}
 Methyl Hydrate - Per Litre      | {63,NULL}
 Mitsu 90mm ODEX Pilot Bit       | {3,NULL}
 NWJ Long Saver Sub Pin x Box    | {70,13}
(6 rows)