我有一个像下面这样的数据模型,它被简化为只显示这个问题( SQL Fiddle 链接在底部):
人在数据库中表示为具有名称和多个属性的元表行,这些属性作为键值对存储在数据表中(键和值在不同的列中)。
预期结果
现在我想检索具有所有属性的所有用户。属性应作为json对象返回到单独的列中。例如:
name, data
Florian, { "age":23, "color":"blue" }
Markus, { "age":24, "color":"green" }
我的方法
现在我的问题是,我找不到在postgres中创建键值对的方法。我试过以下:
SELECT
name,
array_to_json(array_agg(row(d.key, d.value))) AS data
FROM meta AS m
JOIN (
SELECT d.fk_id, d.key, d.value AS value FROM data AS d
) AS d
ON d.fk_id = m.id
GROUP BY m.name;
但它将此作为数据列返回:
[{"f1":"age","f2":24},{"f1":"color","f2":"blue"}]
其他解决方案
我知道有一个函数crosstab
,它使我能够将数据表转换为一个键作为列,将值作为行表。但这不是动态的。我不知道一个人在数据表中有多少属性。所以这不是一个选择。
我还可以使用两个行值创建一个类似json的字符串并聚合它们。但也许有一个更好的解决方案。
不,不可能改变数据模型,因为真实数据模型已经在多方使用。
SQLFiddle
检查并测试我为此问题创建的小提琴: http://sqlfiddle.com/#!15/bd579/14
答案 0 :(得分:6)
试试这个:
select
name,
json_object(array_agg(key), array_agg(replace(value::text, '"', ''))) as data
from data
join meta on fk_id = id
group by 1
Postgres 9.4中引入了json_object(keys text[], values text[])
功能。
答案 1 :(得分:0)
当我需要更新一些JSON并删除数据库中的一些元素时,我遇到了同样的问题。下面的查询对我来说效果很好,因为它保留了字符串引号,但没有将它们添加到数字中。
select
'{' || substr(x.arr, 3, length(x.arr) - 4) || '}'
from
(
select
replace(replace(cast(array_agg(xx) as varchar), '\"', '"'), '","', ', ') as arr
from
(
select
elem.key,
elem.value,
'"' || elem.key || '":' || elem.value as xx
from
quote q
cross join
json_each(q.detail::json -> 'bQuoteDetail'-> 'quoteHC'->0) as elem
where
elem.key != 'allRiskItems'
) f
) x