英文:
How to groupBy in postgres with jsonb column to mimic an EAV count table?
问题
我有一个类似这样的jsonb列:
Id | Data |
---|---|
1 | {state: ["CA", "NY"], county:["Los Angeles"]} |
2 | {city: ["Kansas City"], zipCode: "12345"} |
3 | {state: ["CO, WA"], zipCode: "5212"} |
但我以前的数据结构是这样的:
Id | Attribute | Value |
---|---|---|
1 | state | CA |
1 | state | NY |
2 | city | Kansas City |
等等...
以前我只需要编写像这样的简单查询:
SELECT attribute, value, count(*)
FROM table
GROUP BY attribute, value;
输出结果将会是:
Attribute | Value | Count |
---|---|---|
county | New York County | 11 |
city | Kansas City | 22 |
state | CA | 15 |
zip | 100010 | 21 |
state | NY | 5 |
我正在尝试生成与上面相同的表格,但使用jsonb表格时我遇到了问题。
我已经尝试使用jsonb_each_text
,如下所示:
with t1 as
(select jsonb_each_text(facets) as rec from document_template_facets)
select (rec).key, sum((rec).value::int) from t1 group by (rec).key;
问题是它不适用于我的数据中的数组类型,如城市、县等等... 有没有办法在上面的查询中将数组展平以使计数工作?
英文:
I have a jsonb column that looks like this:
Id | Data |
---|---|
1 | {state: ["CA", "NY"], county:["Los Angeles"]} |
2 | {city: ["Kansas City"], zipCode: "12345"} |
3 | {state: ["CO, WA"], zipCode: "5212"} |
But I used to have a data structure like so:
Id | Attribute | Value |
---|---|---|
1 | state | CA |
1 | state | NY |
2 | city | Kansas City |
etc...
I used to just be able to write a simple query like this:
SELECT attribute, value, count(*)
FROM table
GROUP BY attribute, value;
and the output would yield:
Attribute | Value | Count |
---|---|---|
county | New York County | 11 |
city | Kansas City | 22 |
state | CA | 15 |
zip | 100010 | 21 |
state | NY | 5 |
I'm trying to generate the same table above but with the jsonb table but I'm having trouble getting the desired output.
I've tried using jsonb_each_text like so:
with t1 as
(select jsonb_each_text(facets) as rec from document_template_facets)
select (rec).key, sum((rec).value::int) from t1 group by (rec).key;
The problem is that it doesn't work for array types in my data like city, county, etc... Any way to get the arrays to be flattened in the query above to get the count to work?
答案1
得分: 2
jsonb_each_text()
函数返回行,因此必须位于查询的 from
部分。可以使用 cross join lateral
完成这一操作。
以下查询返回您想要的结果。jsonb_array_elements_text
内的 case
处理数据中的标量值,如 zipCode
元素,将其转换为单元素数组:
with expand_keys as (
select id, k, a
from tab
cross join lateral jsonb_each(data) as j(k, a)
), expand_arrays as (
select id, k, a, el
from expand_keys
cross join lateral
jsonb_array_elements_text(
case jsonb_typeof(a)
when 'array' then a
else jsonb_build_array(a)
end
) as ar(el)
)
-- select * from expand_arrays; --运行此行来查看中间结果
select k as attribute, el as value, count(*) as cnt
from expand_arrays
group by k, el;
英文:
The jsonb_each_text()
function returns rows, so it has to be in the from
part of your query. Do that with a cross join lateral
.
The below query returns what you want. The case
within the jsonb_array_elements_text
handles scalar values like the zipCode
elements in your data by turning those into single-element arrays:
with expand_keys as (
select id, k, a
from tab
cross join lateral jsonb_each(data) as j(k, a)
), expand_arrays as (
select id, k, a, el
from expand_keys
cross join lateral
jsonb_array_elements_text(
case jsonb_typeof(a)
when 'array' then a
else jsonb_build_array(a)
end
) as ar(el)
)
-- select * from expand_arrays; --run this, instead, to see interim results
select k as attribute, el as value, count(*) as cnt
from expand_arrays
group by k, el;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论