如何将JSON数组转换为Postgres中的行


77

我在我的postgres数据库中存储了一个json数组。json看起来像这样:

    [
        {
            "operation": "U",
            "taxCode": "1000",
            "description": "iva description",
            "tax": "12"
        },
        {
            "operation": "U",
            "taxCode": "1001",
            "description": "iva description",
            "tax": "12"
        },
        {
            "operation": "U",
            "taxCode": "1002",
            "description": "iva description",
            "tax": "12"
        }
    ]

现在,我需要选择数组,以便任何元素都位于查询结果的不同行中。因此,我执行的SELECT语句必须以这种方式返回数据:

 data
--------------------------------------------------------------------------------------
 { "operation": "U", "taxCode": "1000", "description": "iva description", "tax":"12"}
 { "operation": "U", "taxCode": "1001", "description": "iva description", "tax":"12"}
 { "operation": "U", "taxCode": "1002", "description": "iva description", "tax":"12"}

我尝试使用该unnest()功能

SELECT unnest(json_data::json)
FROM my_table

但它不接受jsonb类型


11
unnest()适用于PostgreSQL的数组类型。使用 json_array_elements(json)jsonb_array_elements(jsonb)9.3 + ),(9.4+)或json[b]_array_elements_text(json[b])(9.4+)
pozs

谢谢。如果您提出问题,我可以接受。
k4ppa

Answers:


75

我将pozs最初写的答案发布在评论部分。

unnest() 适用于PostgreSQL的数组类型。

而是可以使用以下功能之一:

  • json_array_elements(json) (9.3+)
  • jsonb_array_elements(jsonb) (9.4+)
  • json[b]_array_elements_text(json[b]) (9.4+)

范例

select * from json_array_elements('[1,true, [2,false]]')

产值

 -------------
 | 1         |
 -------------
 | true      |
 -------------
 | [2,false] |
 -------------

这里可以找到v9.4的文档。


1
还值得一提的是,带有“ _text”的函数删除了JSON字符串中令人讨厌的引号
Roman M

45

比较困难的例子:

假设您有一个表,其中的行各包含jsonb数组,并且希望对所有这些数组进行splat(或嵌套),并对其中包含的记录进行一些汇总计算。

表格(设为categories):

 id | specifics (jsonb)
-----------------------------------------------------------------------------------
  1 | [{"name": "Brand", "required": true}, {"name": "Color", "required": false}]
  2 | [{"name": "Brand", "required": false}, {"name": "Color", "required": false}]

因此,如果要计算多少个所需的详细信息,则需要使用以下查询:

SELECT specs.name, COUNT(*) AS total
FROM 
  categories, 
  jsonb_to_recordset(categories.specifics) AS specs(name jsonb, required boolean)
WHERE 
  specs.required = TRUE
  -- AND any other restrictions you need
GROUP BY specs.name
ORDER BY total DESC;

FROM x, function(x.column)横向连接的简化形式,可以有效地将categories虚拟行中的每一行与jsonb_to_recordset同一行中jsonb数组中的函数创建的虚拟表进行连接。

结果将是:

 name  | total
---------------
 Brand |     1

链接到DB Fiddle:https : //www.db-fiddle.com/f/c4xZcEgg9dsPVDtE7Keovv/0


使用横向连接的一个很好的例子
学习者

38

我建议您使用json_to_recordset命令。您的SQL应为:

select *
from json_to_recordset('[{"operation":"U","taxCode":1000},{"operation":"U","taxCode":10001}]')
as x("operation" text, "taxCode" int);

输出为:

------------------------
|   |operation|taxCode |
------------------------
| 1 |   "U"   |   1000 |
------------------------
| 2 |   "U"   |  10001 |
------------------------

该示例的列(或JSON键)可以自由地进一步扩展。


物体上怎么可能?表示我要从json_to_recordset('{“ operation”:“ U”,“ taxCode”:1000}')中将select *转换为x(“ operation”文本,“ taxCode” int); 这但json_to_recordset不起作用
Sherin Green

优秀的!谢谢。
查理木匠
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.