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
列的数据类型people
是json
,就像 的结果一样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 BY
on text
data 也比 on 便宜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
Run Code Online (Sandbox Code Playgroud)
从查询中排除违规行。
有关的:
基于@ypercube\xe1\xb5\x80\xe1\xb4\xb9评论我最终得到:
\n\nSELECT 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
.
归档时间: |
|
查看次数: |
18948 次 |
最近记录: |