如何取消嵌套和 GROUP BY JSON 数组的元素?

Bax*_*Bax 9 postgresql group-by array json

给定band表格,其中一json列包含一个数组:

id | people
---+-------------
1  | ['John', 'Thomas']
2  | ['John', 'James']
3  | ['James', 'George']
Run Code Online (Sandbox Code Playgroud)

如何列出每个名称所属的乐队数量?
期望的输出:

name   | count
-------+------------
John   | 2
James  | 2
Thomas | 1
George | 1
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 10

列的数据类型peoplejson,就像 的结果一样json_array_elements(people)。并且=该数据类型没有相等运算符 ( ) json。所以你也不能运行GROUP BY它。更多的:

jsonb有一个相等运算符,因此您答案中的“解决方法”是强制转换为jsonb并使用等效的jsonb_array_elements(). 演员阵容增加成本:

jsonb_array_elements(people::jsonb)
Run Code Online (Sandbox Code Playgroud)

从 Postgres 9.4 开始,我们也json_array_elements_text(json)将数组元素返回为text. 有关的:

所以:

SELECT p.name, count(*) AS c
FROM   band b, json_array_elements_text(b.people) p(name)
GROUP  BY p.name;
Run Code Online (Sandbox Code Playgroud)

获取名称text而不是jsonb对象(文本表示中的双引号)似乎更方便,并且您的“所需输出”表明您希望/需要text在结果中开始。

GROUP BYon textdata 也比 on 便宜jsonb,因此出于两个原因,这种替代“解决方法”应该更快。(用 测试EXPLAIN (ANALYZE, TIMING OFF)。)

作为记录,您的原始答案没有任何问题。逗号 ( ,) 与CROSS JOIN LATERAL. 早先在标准 SQL 中定义并不会使它变得低劣。看:

也不是更容易移植到其他RDBMS,由于jsonb_array_elements()json_array_elements_text()无法移植到其他RDBMS,首先,这也是无关紧要的。CROSS JOIN LATERALIMO的简短查询并没有变得更清楚,但最后一点只是我的个人意见。

我使用了更明确的表和列别名p(name)以及表限定引用p.name来防止可能的重复名称。name是一个如此常用的词,它也可能作为基础表中的列名弹出band,在这种情况下,它会默默地解析为band.name。简单形式json_array_elements_text(people) name只附加一个别名,列名仍然value是函数返回的。但是在列表中使用时name解析为它的单列。它恰好按预期工作。但是真正的列名(如果应该存在)将首先绑定。虽然在给定的例子中不会咬人,但在其他情况下它可能是一个上膛的脚踏枪valueSELECTnameband.name

不要使用通用的“名称”作为标识符开始。也许那只是为了简单的测试用例。


如果该列people可以包含除普通JSON 数组之外的任何内容,则任一查询都会触发异常。如果您不能保证数据完整性,您可能需要使用以下方法进行防御json_typeof()

SELECT p.name, count(*) AS c
FROM   band b, json_array_elements_text(b.people) p(name)
WHERE  json_typeof(b.people) = 'array'
GROUP  BY 1; -- optional short syntax since you seem to prefer short syntax
Run Code Online (Sandbox Code Playgroud)

从查询中排除违规行。

有关的:


Bax*_*Bax 6

基于@ypercube\xe1\xb5\x80\xe1\xb4\xb9评论我最终得到:

\n\n
SELECT name, count(*) as c\nFROM band \nCROSS JOIN LATERAL jsonb_array_elements(people::jsonb) as name\nGROUP BY name;\n
Run Code Online (Sandbox Code Playgroud)\n\n

只是jsonb_array_elements用来代替unnest.

\n