我有两个Postgres SQL查询返回JSON数组:
Q 1:
[
{"id": 1, "a": "text1a", "b": "text1b"},
{"id": 2, "a": "text2a", "b": "text2b"},
{"id": 2, "a": "text3a", "b": "text3b"},
...
]
Q2:
[
{"id": 1, "percent": 12.50},
{"id": 2, "percent": 75.00},
{"id": 3, "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?
答案 0 :(得分:6)
假设数据类型jsonb
并且您希望合并每个共享相同“id”值的JSON数组的记录。
使新的concatenate operator ||
for jsonb
values:
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);
FULL [OUTER] JOIN
确保您不会丢失其他数组中没有匹配的记录。
类型jsonb
具有方便的属性,只保留记录中每个键的最新值。因此,结果中的重复“id”键会自动合并。
Postgres 9.5手册也建议:
注意:
||
运算符连接顶层的元素 每个操作数。它不会递归运行。例如,如果 两个操作数都是具有公共键字段名称的对象,值为 结果中的字段只是右手操作数的值。
有点不方便。我的想法是提取数组元素,然后提取所有键/值对,UNION
两个结果,聚合成每个id值的一个新的jsonb
值,最后聚合成一个数组。
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
作为结果)。测试哪种情况更快。
相关:
答案 1 :(得分:1)
对于任何单个jsonb元素,这个concat ||
运算符的使用对我来说非常适用于strip_nulls,另一个技巧是将结果转换回jsonb(不是数组)。
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"}
正确输入jsonb