给出一个EAV结构的结果集,例如:
id | attributeName | stringValue | intValue | BooleanValue
---------------------------------------------------------------
1 stringFoo v1
1 stringFooList v2
1 stringFooList v3
1 intFoo 10
1 intFooList 10
1 intFooList 20
1 booleanFoo true
1 booleanFooList true
1 booleanFooList true
如何将所有属性和值对选择为JSON / JSONB格式的单个值,就像这样:
{
"stringFoo" : "v1" ,
"stringFooList" : ["v2","v3"] ,
"intFoo" : 10 ,
"intFooList" : [10,20],
"booleanFoo" : true,
"booleanFooList" : [true,true]
}
如果某个属性(例如stringFooList
)具有多个属性值,它将把它格式化为JSON数组。
我正在使用PostgreSQL 9.6
答案 0 :(得分:1)
您可以执行以下操作:
select id, jsonb_object_agg(att, value)
from (
select id,
attributename as att,
case
when count(*) > 1 then
jsonb_agg(coalesce(stringvalue,intvalue::text,booleanvalue::text))
else
to_jsonb(min(coalesce(stringvalue,intvalue::text,booleanvalue::text)))
end as value
from eav
group by id, attributename
) t
group by id;
内部选择将多个值聚合到一个JSON数组中,将单个值聚合到JSON标量值中。然后,外部查询将为所有行构建一个JSON值。
答案 1 :(得分:0)
@a_horse_with_no_name
的回答给了我一个很好的开始。我扩展了他/她的答案,并提出了以下查询,以使JSON数组中的元素具有与PostgreSQL中定义的数据类型相同的数据类型。
select id, jsonb_object_agg(att,
case
when strval is not null then strval
when intvalue is not null then intvalue
else boolVal
end
)
from (
select id,
attributename as att,
case when count(*) > 1 then
jsonb_agg(stringvalue) filter (where stringvalue is not null)
else
to_jsonb(min(stringvalue) filter (where stringvalue is not null))
end as strVal,
case when count(*) > 1 then
jsonb_agg(intvalue) filter (where intvalue is not null)
else
to_jsonb(min(intvalue) filter (where intvalue is not null))
end as intvalue,
case when count(*) > 1 then
jsonb_agg(booleanvalue) filter (where booleanvalue is not null)
else
to_jsonb(bool_and(booleanvalue) filter (where booleanvalue is not null))
end as boolVal
from eav
group by id, attributename
) t
group by id;