在Postgres中创建JSON

时间:2018-08-15 08:55:56

标签: sql json postgresql

在我们的数据库中,我们有几个表,它们的构成略有不同。我们想在postgres中构建1个函数,该函数可以使用某种特定的结构从中生成JSON。

这是两个示例表:

CREATE TEMPORARY TABLE tmp_experience( level 
character varying , value numeric , score 
numeric, mean numeric );

INSERT INTO tmp_experience( level , value , 
score , mean ) VALUES ( 'high' , 0.23 , 30 , 
0.45 ) , ('low' , 0.63 , 45 , 0.56 );

CREATE TEMPORARY TABLE tmp_gender( level 
character varying , value numeric , 
percentage numeric );

INSERT INTO tmp_gender( level , value , 
percentage ) VALUES ( 'male' , 2.23 , 35 ) , 
('female' , 1.63 , 65  );

我们要制作以下两个JSON:

{
  "high": {
    "value": 0.23,
    "score": 30,
    "mean": 0.45
  },
  "low": {
    "value": 0.63,
    "score": 45,
    "mean": 0.56
  }
}

{
  "male": {
    "value": 2.23,
    "score": 35
  },
  "female": {
    "value": 1.63,
    "score": 65
  }
}

我们希望Postgres中有一个函数可以做到这一点。我以为这是相对简单的(也许是这样!),但是我根本不知道该怎么做。

1 个答案:

答案 0 :(得分:0)

使用聚合函数jsonb_object_agg():

select jsonb_object_agg(level, to_jsonb(t)- 'level')
from tmp_experience t;

                                            jsonb_object_agg                                             
---------------------------------------------------------------------------------------------------------
 {"low": {"mean": 0.56, "score": 45, "value": 0.63}, "high": {"mean": 0.45, "score": 30, "value": 0.23}}
(1 row)

select jsonb_object_agg(level, to_jsonb(t)- 'level')
from tmp_gender t

                                     jsonb_object_agg                                     
------------------------------------------------------------------------------------------
 {"male": {"value": 2.23, "percentage": 35}, "female": {"value": 1.63, "percentage": 65}}
(1 row) 

更新

您需要尽可能多的SELECT。您可以将派生表(FROM子句中的子查询)用于嵌套聚合:

-- jsonb_pretty() not necessary, used for readable output
select jsonb_pretty(jsonb_object_agg(country, levels)) as countries
from (
    select country, jsonb_object_agg(level, to_jsonb(t)- 'country'- 'level') as levels
    from tmp_experience t
    group by country
    ) s

或常用表表达式:

with levels as (
    select country, jsonb_object_agg(level, to_jsonb(t)- 'country'- 'level') as levels
    from tmp_experience t
    group by country
)
select jsonb_pretty(jsonb_object_agg(country, levels)) as countries
from levels;

Working example in rextester.