Answers:
列的数据类型people
为json
,结果是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 BY
对text
数据也比便宜的jsonb
,所以这种替代“解决办法”应该快有两个原因。(使用进行测试EXPLAIN (ANALYZE, TIMING OFF)
。)
记录下来,您的原始答案没有错。逗号(,
)与一样“正确” CROSS JOIN LATERAL
。在标准SQL中较早地定义并不会使其劣等。看到:
也不是更容易移植到其他RDBMS,由于jsonb_array_elements()
或json_array_elements_text()
无法移植到其他RDBMS,首先,这也是无关紧要的。简短的查询对CROSS JOIN LATERAL
IMO 并没有更清晰的了解,但最后一点只是我个人的看法。
我使用了更明确的表和列别名p(name)
以及表限定的引用p.name
来防止可能出现的重复名称。name
是一个非常常用的词,它也可能会作为基础表中的列名弹出band
,在这种情况下,它将默默地解析为band.name
。简单形式json_array_elements_text(people) name
只附加一个表别名,列名仍然是value
,从函数返回。但是在列表中使用时name
解析为单列。它恰好按预期工作。但是,真正的列名(如果应该存在)将首先绑定。尽管在给定的示例中不会被攻击,但在其他情况下,它可能是一柄装载的脚枪。value
SELECT
name
band.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
从查询中排除违规行。
有关: