如何在两个JSON数组中合并记录?

如何在两个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}, ... ]

我有两个返回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},
  ...
]
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
)。测试哪一个对您的案例更快

相关的:


对于任何单个jsonb元素,使用concat
|
操作符可以很好地处理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"}