无法从 JSON_ARRAY_ELEMENTS() 获取所有值
Unable to get all the values from JSON_ARRAY_ELEMENTS()
Table 样本数据:
create table tbl_jsdata
(
id int,
p_id int,
field_name text,
field_value text
);
insert into tbl_jsdata values
(1,101,'Name','Sam'),
(2,101,'City','Dubai'),
(3,101,'Pin','1235'),
(4,101,'Country','UAE'),
(5,102,'Name','Sam'),
(6,102,'City','Dubai'),
(7,102,'Name','Sam Jack'),
(8,102,'Name','Test'),
(9,102,'Name',null);
json_agg查询:
drop table if exists tempJSData;
select p_id,
json_build_array(json_object_agg(field_name, field_value)) into tempJSData
from tbl_jsdata
group by p_id;
得到结果:
select p_id,(json_array_elements(json_build_array)->>'Name')::text Namess
from tempJSData
p_id Namess
---------------------------------
101 Sam
102
预期结果:
p_id Namess
---------------------------------
101 Sam
102 Sam
102 Sam Jack
102 Test
102
我认为这是因为您没有创建 Name
.
的数组
如果您检查您的查询
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
结果是
p_id | json_build_array
------+---------------------------------------------------------------------------------------------
101 | [{ "Name" : "Sam", "City" : "Dubai", "Pin" : "1235", "Country" : "UAE" }]
102 | [{ "Name" : "Sam", "City" : "Dubai", "Name" : "Sam Jack", "Name" : "Test", "Name" : null }]
(2 rows)
Name
字段有多个相邻条目。以下 json_array_elements(json_build_array)->>'Name'
将仅获取第一个条目。我建议首先创建一个基于 p_id
和 field_name
的数组
with array_built as (
select p_id,field_name,
array_agg(field_value) field_value
from tbl_jsdata
group by p_id, field_name
)
select p_id,
jsonb_object_agg(field_name, field_value)
from array_built
group by p_id
;
结果可以优化,因为它创建一个数组,即使只有一个值
p_id | jsonb_object_agg
------+---------------------------------------------------------------------------
101 | {"Pin": ["1235"], "City": ["Dubai"], "Name": ["Sam"], "Country": ["UAE"]}
102 | {"City": ["Dubai"], "Name": ["Sam", "Sam Jack", "Test", null]}
(2 rows)
但现在您可以正确解析它,整个查询是
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
with array_built as (
select p_id,field_name,
array_agg(field_value) field_value
from tbl_jsdata
group by p_id, field_name
), agg as (
select p_id,
jsonb_object_agg(field_name, field_value) json_doc
from array_built
group by p_id
)
select p_id, jsonb_array_elements(json_doc->'Name') from agg;
;
预期结果为
p_id | jsonb_array_elements
------+----------------------
101 | "Sam"
102 | "Sam"
102 | "Sam Jack"
102 | "Test"
102 | null
(5 rows)
您可以使用 json_each_text
来提取数组的值,并在 WHERE
子句中仅过滤您想要的 key
:
SELECT p_id,j.value
FROM tempJSData, json_each_text(json_build_array->0) j
WHERE j.key = 'Name';
p_id | value
------+----------
101 | Sam
102 | Sam
102 | Sam Jack
102 | Test
102 |
(5 rows)
注意:此查询假定您的 json 格式是最终格式。如果不是,请考虑创建一个 Name
数组而不是一个包含名称的对象数组:name[foo,bar]
而不是 [name:foo,name:bar]
。 Ftisiot 的回答提出了一个很好的观点。
演示:db<>fiddle
您的 JSON 聚合本质上是无效的,因为您正在创建一个 JSON 值,其中同一个键出现不止一次。如果您使用了推荐的 jsonb
数据类型,则重复键将被删除。
我认为这种聚合更有意义:
create table tempjsdata
as
select p_id,
jsonb_agg(jsonb_build_object(field_name, field_value)) as names
from tbl_jsdata
group by p_id
以上生成以下结果:
p_id | names
-----+---------------------------------------------------------------------------------------------
101 | [{"Name": "Sam"}, {"City": "Dubai"}, {"Pin": "1235"}, {"Country": "UAE"}]
102 | [{"Name": "Sam"}, {"City": "Dubai"}, {"Name": "Sam Jack"}, {"Name": "Test"}, {"Name": null}]
那么你可以使用:
select p_id,
x.*
from tempjsdata
cross join lateral (
select x.item ->> 'Name'
from jsonb_array_elements(t.names) as x(item)
where x.item ? 'Name'
) x
Table 样本数据:
create table tbl_jsdata
(
id int,
p_id int,
field_name text,
field_value text
);
insert into tbl_jsdata values
(1,101,'Name','Sam'),
(2,101,'City','Dubai'),
(3,101,'Pin','1235'),
(4,101,'Country','UAE'),
(5,102,'Name','Sam'),
(6,102,'City','Dubai'),
(7,102,'Name','Sam Jack'),
(8,102,'Name','Test'),
(9,102,'Name',null);
json_agg查询:
drop table if exists tempJSData;
select p_id,
json_build_array(json_object_agg(field_name, field_value)) into tempJSData
from tbl_jsdata
group by p_id;
得到结果:
select p_id,(json_array_elements(json_build_array)->>'Name')::text Namess
from tempJSData
p_id Namess
---------------------------------
101 Sam
102
预期结果:
p_id Namess
---------------------------------
101 Sam
102 Sam
102 Sam Jack
102 Test
102
我认为这是因为您没有创建 Name
.
如果您检查您的查询
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
结果是
p_id | json_build_array
------+---------------------------------------------------------------------------------------------
101 | [{ "Name" : "Sam", "City" : "Dubai", "Pin" : "1235", "Country" : "UAE" }]
102 | [{ "Name" : "Sam", "City" : "Dubai", "Name" : "Sam Jack", "Name" : "Test", "Name" : null }]
(2 rows)
Name
字段有多个相邻条目。以下 json_array_elements(json_build_array)->>'Name'
将仅获取第一个条目。我建议首先创建一个基于 p_id
和 field_name
的数组
with array_built as (
select p_id,field_name,
array_agg(field_value) field_value
from tbl_jsdata
group by p_id, field_name
)
select p_id,
jsonb_object_agg(field_name, field_value)
from array_built
group by p_id
;
结果可以优化,因为它创建一个数组,即使只有一个值
p_id | jsonb_object_agg
------+---------------------------------------------------------------------------
101 | {"Pin": ["1235"], "City": ["Dubai"], "Name": ["Sam"], "Country": ["UAE"]}
102 | {"City": ["Dubai"], "Name": ["Sam", "Sam Jack", "Test", null]}
(2 rows)
但现在您可以正确解析它,整个查询是
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
select p_id,
json_build_array(json_object_agg(field_name, field_value))
from tbl_jsdata
group by p_id;
with array_built as (
select p_id,field_name,
array_agg(field_value) field_value
from tbl_jsdata
group by p_id, field_name
), agg as (
select p_id,
jsonb_object_agg(field_name, field_value) json_doc
from array_built
group by p_id
)
select p_id, jsonb_array_elements(json_doc->'Name') from agg;
;
预期结果为
p_id | jsonb_array_elements
------+----------------------
101 | "Sam"
102 | "Sam"
102 | "Sam Jack"
102 | "Test"
102 | null
(5 rows)
您可以使用 json_each_text
来提取数组的值,并在 WHERE
子句中仅过滤您想要的 key
:
SELECT p_id,j.value
FROM tempJSData, json_each_text(json_build_array->0) j
WHERE j.key = 'Name';
p_id | value
------+----------
101 | Sam
102 | Sam
102 | Sam Jack
102 | Test
102 |
(5 rows)
注意:此查询假定您的 json 格式是最终格式。如果不是,请考虑创建一个 Name
数组而不是一个包含名称的对象数组:name[foo,bar]
而不是 [name:foo,name:bar]
。 Ftisiot 的回答提出了一个很好的观点。
演示:db<>fiddle
您的 JSON 聚合本质上是无效的,因为您正在创建一个 JSON 值,其中同一个键出现不止一次。如果您使用了推荐的 jsonb
数据类型,则重复键将被删除。
我认为这种聚合更有意义:
create table tempjsdata
as
select p_id,
jsonb_agg(jsonb_build_object(field_name, field_value)) as names
from tbl_jsdata
group by p_id
以上生成以下结果:
p_id | names
-----+---------------------------------------------------------------------------------------------
101 | [{"Name": "Sam"}, {"City": "Dubai"}, {"Pin": "1235"}, {"Country": "UAE"}]
102 | [{"Name": "Sam"}, {"City": "Dubai"}, {"Name": "Sam Jack"}, {"Name": "Test"}, {"Name": null}]
那么你可以使用:
select p_id,
x.*
from tempjsdata
cross join lateral (
select x.item ->> 'Name'
from jsonb_array_elements(t.names) as x(item)
where x.item ? 'Name'
) x