【问题标题】:Using json_array_elements() to break out rows with elements of JSON array使用 json_array_elements() 用 JSON 数组的元素分解行
【发布时间】:2022-01-20 21:24:42
【问题描述】:

我有一个以下格式的表格,只有一列。总共有大约 700 个条目,这里有 5 个示例:

{"year":"2021","category":"chemistry","laureates":[{"id": "1002", "firstname": "Benjamin", "surname": "List", "motivation": "\"for the development of asymmetric organocatalysis\"", "share": "2"}, {"id": "1003", "firstname": "David", "surname": "MacMillan", "motivation": "\"for the development of asymmetric organocatalysis\"", "share": "2"}],"reason":null}
{"year":"2021","category":"economics","laureates":[{"id": "1007", "firstname": "David", "surname": "Card", "motivation": "\"for his empirical contributions  to labour economics\"", "share": "2"}, {"id": "1008", "firstname": "Joshua", "surname": "Angrist", "motivation": "\"for their methodological contributions to the analysis  of causal relationships\"", "share": "4"}, {"id": "1009", "firstname": "Guido", "surname": "Imbens", "motivation": "\"for their methodological contributions to the analysis  of causal relationships\"", "share": "4"}],"reason":null}
{"year":"2021","category":"literature","laureates":[{"id": "1004", "firstname": "Abdulrazak", "surname": "Gurnah", "motivation": "\"for his uncompromising and compassionate penetration of the effects of colonialism and the  fate of the refugee in the gulf between cultures and continents\"", "share": "1"}],"reason":null}
{"year":"2021","category":"peace","laureates":[{"id": "1005", "firstname": "Maria", "surname": "Ressa", "motivation": "\"for their efforts to safeguard freedom of expression, which  is a precondition for democracy and lasting peace\"", "share": "2"}, {"id": "1006", "firstname": "Dmitry", "surname": "Muratov", "motivation": "\"for their efforts to safeguard freedom of expression, which  is a precondition for democracy and lasting peace\"", "share": "2"}],"reason":null}
{"year":"2021","category":"physics","laureates":[{"id": "999", "firstname": "Syukuro", "surname": "Manabe", "motivation": "\"for the physical modelling of Earth’s climate, quantifying variability and reliably predicting global warming\"", "share": "4"}, {"id": "1000", "firstname": "Klaus", "surname": "Hasselmann", "motivation": "\"for the physical modelling of Earth’s climate, quantifying variability and reliably predicting global warming\"", "share": "4"}, {"id": "1001", "firstname": "Giorgio", "surname": "Parisi", "motivation": "\"for the discovery of the interplay of disorder and fluctuations in physical systems from atomic to planetary scales\"", "share": "2"}],"reason":"for groundbreaking contributions to our understanding of complex physical systems"}

我想以这种格式打印输出:

year category r
"2021" "chemistry" {"id": "1002", "firstname": "Benjamin", "surname": "List", "motivation": ""for the development of asymmetric organocatalysis"", "share": "2"}
"2021" "chemistry" {"id": "1003", "firstname": "David", "surname": "MacMillan", "motivation": ""for the development of asymmetric organocatalysis"", "share": "2"}
"2021" "economics" {"id": "1007", "firstname": "David", "surname": "Card", "motivation": ""for his empirical contributions to labour economics"", "share": "2"}
"2021" "economics" {"id": "1008", "firstname": "Joshua", "surname": "Angrist", "motivation": ""for their methodological contributions to the analysis of causal relationships"", "share": "4"}
"2021" "economics" {"id": "1009", "firstname": "Guido", "surname": "Imbens", "motivation": ""for their methodological contributions to the analysis of causal relationships"", "share": "4"}

我能够通过以下查询获得上面的输出:

SELECT tuple->'year' AS year, tuple->'category' AS category,json_array_elements(tuple->'laureates') FROM prizes LIMIT 5;

我想要的是用如下查询输出表中的所有值:

SELECT tuple->'year' AS year, tuple->'category' AS category,json_array_elements(tuple->'laureates') FROM prizes;

当我运行这个查询时,我得到了这个错误:

cannot call json_array_elements on a scalar

我不明白为什么会发生这种情况以及我将如何输出所有可能的元素。

【问题讨论】:

  • 这意味着您的表格中有一些行的laureates 列不是列表。

标签: sql json postgresql


【解决方案1】:

由于json_array_elements() 只能用于 JSON数组、拆分案例和UNION ALL

SELECT tuple->'year' AS year, tuple->'category' AS category, json_array_elements(tuple->'laureates') AS r
FROM   prizes
WHERE  json_typeof(tuple->'laureates') = 'array'
UNION ALL
SELECT tuple->'year' AS year, tuple->'category' AS category, tuple->'laureates'
FROM   prizes
WHERE  json_typeof(tuple->'laureates') IS DISTINCT FROM 'array';

The manual:

json_typeof ( json ) → text
[...]

以文本字符串形式返回顶级 JSON 值的类型。 可能的类型是objectarraystringnumberboolean、 和null。 (null 结果不应与 SQL 混淆 无效的; [...])

注意在第二条腿中使用IS DISTINCT FROM。运算符<> 将消除带有(tuple->'laureates') IS NULL 的行。

jsonb_path_query() 在 Postgres 12 或更高版本中

使用jsonb_path_query(),我们不需要拆分案例 (like Edouard suggested)。但是要包含没有laureate 的行,我们需要LEFT JOIN 来添加它:

SELECT p.id, p.tuple->>'year' AS year, p.tuple->>'category' AS category, l.r
FROM   prizes p
LEFT   JOIN LATERAL jsonb_path_query((tuple->'laureates')::jsonb, '$[*]', '{"foo":"bar"}') AS l(r) ON true;

db小提琴here

见:

【讨论】:

    【解决方案2】:

    如果您使用的是 PostGreSQL 版本 12 或更高版本,那么您可以使用 jsonb_path_query 而不是 json_array_elements,如下所示:

    SELECT tuple->>'year'
         , tuple->>'category'
         , jsonb_path_query((tuple->'laureates') :: jsonb, '$[*]')
      FROM prizes
    

    jsonb_path_query 是 json 数组时会分解 tuple->'laureates',但当 tuple->'laureates' 不是 json 数组时不会失败。

    dbfiddle查看测试结果。

    请参阅manual 中的 SQL/JSON 路径语言。

    【讨论】:

    • jsonb_path_query() 实际上更优雅。不过,这个公式消除了没有获奖者的行。我添加了替代答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    • 2015-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多