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


8

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

id | people
---+-------------
1  | ['John', 'Thomas']
2  | ['John', 'James']
3  | ['James', 'George']

如何列出每个名字所属的乐队数量?
所需的输出:

name   | count
-------+------------
John   | 2
James  | 2
Thomas | 1
George | 1

Answers:


7

列的数据类型peoplejson,结果是json_array_elements(people)=数据类型没有相等运算符()json。因此,您也无法GROUP BY在其上运行。更多:

jsonb有一个等于运算符,因此答案中的“解决方法”是强制转换为jsonb并使用等价物jsonb_array_elements()。演员表增加成本:

jsonb_array_elements(people::jsonb)

从Postgres 9.4开始,我们还json_array_elements_text(json)返回了数组元素as text。有关:

所以:

SELECT p.name, count(*) AS c
FROM   band b, json_array_elements_text(b.people) p(name)
GROUP  BY p.name;

以名称text代替jsonb对象(在文本表示中用双引号引起)似乎更方便,并且“期望的输出”表示您希望/需要text从结果开始。

GROUP BYtext数据也比便宜的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

从查询中排除违规行。

有关:


4

基于@ypercubeᵀᴹ的评论,我最终得到了:

SELECT name, count(*) as c
FROM band 
CROSS JOIN LATERAL jsonb_array_elements(people::jsonb) as name
GROUP BY name;

只是用来jsonb_array_elements代替unnest


-1

对于MySQL中的某人

SELECT
  JSON_EXTRACT(people, CONCAT('$[', idx, ']')) AS name, count(*) as count
FROM yourtable
JOIN subtable AS indexes
WHERE JSON_EXTRACT(people, CONCAT('$[', idx, '].id')) IS NOT NULL
group by name

带有子表,如:Colum:idx,row:0,1,2,3,4,5,6,7,8,9 ...

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.