arrays - 将 JSONB 数组转换为列

标签 arrays postgresql jsonb postgresql-9.5

我有一个查询返回包含 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"}]

给出这些示例数据,我想要一个查询来生成一个具有模式的表

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 扩展添加到此数据库实例。

最佳答案

第一步。

您可以在 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() 描述 in this post . 您必须使用上述数据创建一个新表才能使用该功能,例如:

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)    

关于arrays - 将 JSONB 数组转换为列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42308897/

相关文章:

postgresql - 估计在 PostgreSQL 中删除列的影响大小

sql - 如何在 Postgresql 中对 JSONB 数组中的值求和?

php - 无法输出多维数组

python - python 代码在数组中不起作用

java - 如何从用 Java 编写的 Azure Function App 连接到 PostgreSQL?

sql - 如何 INSERT - WHERE NOT EXISTS 在另一个具有匹配列的表上?

sql - 如何对 PostgreSQL JSON 字段进行排序

json - 在 PostgreSQL 中更新 jsonb 数据中的多个值

iphone - 在 Objective-C 中复制整数数组的最有效方法是什么?

c++ - 我们可以给指针无符号字符数组赋值吗?