Sql Postgres函数将两个具有重叠键的json对象合并为一个对象

Sql Postgres函数将两个具有重叠键的json对象合并为一个对象,sql,json,postgresql,postgresql-9.3,Sql,Json,Postgresql,Postgresql 9.3,我得到了以下json对象: { "a" : { "0" : 2, "1" : 4, "3" : 6, } "b" : { "2" : 8, "1" : 10, /*note this key exists in "a" too*/ "4" : 12, } } 我希望生成以下对象,然后能够像这样从中提取元素: { "0" : 2, "1"

我得到了以下json对象:

{
    "a" : {
        "0" : 2,
        "1" : 4,
        "3" : 6,
    }
    "b" : {
        "2" : 8,
        "1" : 10, /*note this key exists in "a" too*/
        "4" : 12,
    }
}
我希望生成以下对象,然后能够像这样从中提取元素:

{
        "0" : 2,
        "1" : 10,
        "2" : 8,
        "3" : 6,
        "4" : 12,
}
提取:
对象->'1'
应返回
'10'

基本上,我有两个可能重叠键的数组,我想合并这两个数组,给一个数组优先级


我怎样才能做到这一点?理想情况下,我会调用一个函数,比如
arrayMerge(a,b)
,它给
'a'
'b'

更高的优先级。答案与Postgres 9.4和9.3有关。

示例数据:

create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');
首先,检索具有任意选择优先级的所有对:

select 0 priority, jsonb_each(val->'b') elem
from test_js
union all
select 1 priority, jsonb_each(val->'a') elem
from test_js
order by 1

 priority |  elem  
----------+--------
        0 | (1,10)
        0 | (2,8)
        0 | (4,12)
        1 | (0,2)
        1 | (1,4)
        1 | (3,6)
(6 rows)
接下来,从结果集中选择具有唯一键的元素:

select distinct on ((elem).key) elem
from (
    select 0 priority, jsonb_each(val->'b') elem
    from test_js
    union all
    select 1 priority, jsonb_each(val->'a') elem
    from test_js
    ) sub

  elem  
--------
 (0,2)
 (1,10)
 (2,8)
 (3,6)
 (4,12)
(5 rows)    
最后,将结果聚合为json对象:

select json_object_agg((elem).key, (elem).value) result
from (
    select distinct on ((elem).key) elem
    from (
        select 0, jsonb_each(val->'b') elem
        from test_js
        union all
        select 1, jsonb_each(val->'a') elem
        from test_js
        ) sub
    ) sub

                      result                       
---------------------------------------------------
 { "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)
Postgres 9.3中,您可以使用
string\u agg
模拟
json\u object\u agg

select format('{ %s }', 
    string_agg(format('"%s" : %s', (elem).key, (elem).value), ', '))::json result
from (
    select distinct on ((elem).key) elem
    from (
        select 0, json_each(val->'b') elem
        from test_js
        union all
        select 1, json_each(val->'a') elem
        from test_js
        ) sub
    ) sub

                      result                       
---------------------------------------------------
 { "0" : 2, "1" : 10, "2" : 8, "3" : 6, "4" : 12 }
(1 row)     
顺便说一句,您的json值无效,应该是

{
    "a": {
        "0": 2,
        "1": 4,
        "3": 6
    },
    "b": {
        "1": 10,
        "2": 8,
        "4": 12
    }
}

请使用验证json值。

Postgres 9.5+中,您只需使用内置的连接运算符
|
即可合并json对象

create table test_js(val jsonb);
insert into test_js values ('{"a":{"0":2,"1":4,"3":6},"b":{"1":10,"2":8,"4":12}}');

select (val->'a') || (val->'b') from test_js;
                  ?column?
--------------------------------------------
 {"0": 2, "1": 10, "2": 8, "3": 6, "4": 12}
(1 row)

这是否比简单的
情况下更有效,当合并(a->>'1','-1')='-1'然后合并(b->>'1','-1')或者合并(a->>'1','-1')结束时
?可能在性能上没有很大差异,但很难想象一个查询有几十个这样的比较。答案中的解决方案更一般。纯粹为了讨论的目的,您知道json对象是否在Postgres中进行哈希处理吗?如果是这样,我的
CASE
语句可能会更快,因为它使用现有的哈希表,而不是为新对象构建新的哈希表?当你引用对象的次数增加到无穷大时,你的可能会快得多(我的是O(3n),你的是O(n),其中n是你查询对象的次数,我相信?)是的,这似乎是可能的。对于小的
n
来说,简单的比较可能会快一点。随着
n
的增加,一般查询应该会变得更好。事实上我忘了提到我在读博士后9.3。你有没有什么想法可以不用
json\u object\u agg
?我就把它作为答案吧。
?专栏是怎么回事?