如何在两个JSON数组中合并记录?
我有两个返回JSON数组的Postgres SQL查询: 问题1: 问题2: 我希望结果是两个数组唯一元素的并集:如何在两个JSON数组中合并记录?,json,postgresql,postgresql-9.4,Json,Postgresql,Postgresql 9.4,我有两个返回JSON数组的Postgres SQL查询: 问题1: 问题2: 我希望结果是两个数组唯一元素的并集: [ {"id": 1, "a": "text1a", "b": "text1b", "percent": 12.50}, {"id": 2, "a": "text2a", "b": "text2b", "percent": 75.00}, {"id": 3, "a": "text3a", "b": "text3b", "percent": 12.50}, ... ]
[
{"id": 1, "a": "text1a", "b": "text1b", "percent": 12.50},
{"id": 2, "a": "text2a", "b": "text2b", "percent": 75.00},
{"id": 3, "a": "text3a", "b": "text3b", "percent": 12.50},
...
]
Postgres 9.4中的SQL如何实现这一点?假设数据类型jsonb
,并且您希望合并共享相同“id”值的每个JSON数组的记录
博士后9.5
使用新功能使其更简单:
FULL[OUTER]JOIN
确保不会丢失其他数组中不匹配的记录
类型jsonb
具有方便的属性,只保留记录中每个键的最新值。因此,结果中重复的“id”键将自动合并
Postgres 9.5手册还建议:
注意:|
操作符将元素连接到
它的每个操作数。它不会递归操作。例如,如果
这两个操作数都是具有公共键字段名称(值为)的对象
结果中的字段仅为右侧操作数的值
博士后9.4
有点不方便。我的想法是提取数组元素,然后提取所有键/值对,UNION
两个结果,聚合为单个新的jsonb
每个id值的值,最后聚合为单个数组
SELECT json_agg(j) -- ::jsonb
FROM (
SELECT json_object_agg(key, value)::jsonb AS j
FROM (
SELECT elem->>'id' AS id, x.*
FROM (
SELECT '[
{"id":1, "percent":12.50},
{"id":2, "percent":75.00},
{"id":3, "percent":12.50}]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem, jsonb_each(elem) x
UNION ALL -- or UNION, see below
SELECT elem->>'id' AS id, x.*
FROM (
SELECT '[
{"id": 1, "a": "text1a", "b": "text1b", "percent":12.50},
{"id": 2, "a": "text2a", "b": "text2b", "percent":75.00},
{"id": 3, "a": "text3a", "b": "text3b", "percent":12.50}]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem, jsonb_each(elem) x
) t
GROUP BY id
) t;
转换到jsonb
将删除重复的键。或者,您可以使用UNION
折叠重复项(例如,如果您希望结果是json
)。测试哪一个对您的案例更快
相关的:
|
操作符可以很好地处理strip_nulls和另一个将结果转换回jsonb(而不是数组)的技巧
这就是结果
{"a": "unchanged value", "b": "NEW value", "c": "NEW field"}
哪一个是正确键入的
jsonb
是json数组存储?不确定我是否回答正确。JSON是从SQL查询动态返回的。例如,q1由polls.id=2的polls中的select to_json(answers)返回。这有帮助吗?我冒昧地修复了你的值中的语法错误。这很好。非常感谢你,欧文!
SELECT json_agg(elem1 || elem2) AS result
FROM (
SELECT elem1->>'id' AS id, elem1
FROM (
SELECT '[
{"id":1, "percent":12.50},
{"id":2, "percent":75.00},
{"id":3, "percent":12.50}
]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem1
) t1
FULL JOIN (
SELECT elem2->>'id' AS id, elem2
FROM (
SELECT '[
{"id": 1, "a": "text1a", "b": "text1b", "percent":12.50},
{"id": 2, "a": "text2a", "b": "text2b", "percent":75.00},
{"id": 3, "a": "text3a", "b": "text3b", "percent":12.50}]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem2
) t2 USING (id);
SELECT json_agg(j) -- ::jsonb
FROM (
SELECT json_object_agg(key, value)::jsonb AS j
FROM (
SELECT elem->>'id' AS id, x.*
FROM (
SELECT '[
{"id":1, "percent":12.50},
{"id":2, "percent":75.00},
{"id":3, "percent":12.50}]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem, jsonb_each(elem) x
UNION ALL -- or UNION, see below
SELECT elem->>'id' AS id, x.*
FROM (
SELECT '[
{"id": 1, "a": "text1a", "b": "text1b", "percent":12.50},
{"id": 2, "a": "text2a", "b": "text2b", "percent":75.00},
{"id": 3, "a": "text3a", "b": "text3b", "percent":12.50}]'::jsonb AS js
) t, jsonb_array_elements(t.js) elem, jsonb_each(elem) x
) t
GROUP BY id
) t;
select jsonb_array_elements(jsonb_strip_nulls(jsonb_agg(
'{
"a" : "unchanged value",
"b" : "old value",
"d" : "delete me"
}'::jsonb
|| -- The concat operator works as merge on jsonb, the right operand takes precedence
-- NOTE: it only works one JSON level deep
'{
"b" : "NEW value",
"c" : "NEW field",
"d" : null
}'::jsonb
)));
{"a": "unchanged value", "b": "NEW value", "c": "NEW field"}