在 SQL (Postgres) 中作为 JSON 对象数组返回

Posted

技术标签:

【中文标题】在 SQL (Postgres) 中作为 JSON 对象数组返回【英文标题】:Return as array of JSON objects in SQL (Postgres) 【发布时间】:2014-12-16 16:23:26 【问题描述】:

我有下表MyTable

 id │ value_two │ value_three │ value_four 
────┼───────────┼─────────────┼────────────
  1 │ a         │ A           │ AA
  2 │ a         │ A2          │ AA2
  3 │ b         │ A3          │ AA3
  4 │ a         │ A4          │ AA4
  5 │ b         │ A5          │ AA5

我想查询由value_two 分组的对象数组 value_three, value_four value_two 应该单独出现在结果中。结果应如下所示:

 value_two │                                                                                    value_four                                                                                 
───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 a         │ ["value_three":"A","value_four":"AA", "value_three":"A2","value_four":"AA2", "value_three":"A4","value_four":"AA4"]
 b         │ ["value_three":"A3","value_four":"AA3", "value_three":"A5","value_four":"AA5"]

不管是使用json_agg()还是array_agg()

但我能做的最好的事情是:

with MyCTE as ( select value_two, value_three, value_four from MyTable ) 
select value_two, json_agg(row_to_json(MyCTE)) value_four 
from MyCTE 
group by value_two;

返回:

 value_two │                                                                                    value_four                                                                                 
───────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 a         │ ["value_two":"a","value_three":"A","value_four":"AA", "value_two":"a","value_three":"A2","value_four":"AA2", "value_two":"a","value_three":"A4","value_four":"AA4"]
 b         │ ["value_two":"b","value_three":"A3","value_four":"AA3", "value_two":"b","value_three":"A5","value_four":"AA5"]

在对象中有一个额外的value_two 键,我想摆脱它。我应该使用哪个 SQL (Postgres) 查询?

【问题讨论】:

【参考方案1】:

json_build_object() 在 Postgres 9.4 或更高版本中

jsonb_build_object() 返回jsonb

SELECT value_two, json_agg(json_build_object('value_three', value_three
                                           , 'value_four' , value_four)) AS value_four
FROM   mytable 
GROUP  BY value_two;

The manual:

根据可变参数列表构建 JSON 对象。按照惯例, 参数列表由交替的键和值组成。

适用于任何版本(包括 Postgres 9.3)

row_to_json()ROW 表达式可以解决问题:

SELECT value_two
     , json_agg(row_to_json((value_three, value_four))) AS value_four
FROM   mytable
GROUP  BY value_two;

但是您丢失了原始列名。强制转换为已注册的行类型可以避免这种情况。 (临时表的行类型也可用于临时查询。)

CREATE TYPE foo AS (value_three text, value_four text);  -- once in the same session
SELECT value_two
     , json_agg(row_to_json((value_three, value_four)::foo)) AS value_four
FROM   mytable
GROUP  BY value_two;

或者使用 subselect 代替 ROW 表达式。更详细,但没有类型转换:

SELECT value_two
     , json_agg(row_to_json((SELECT t FROM (SELECT value_three, value_four) t))) AS value_four
FROM   mytable
GROUP  BY value_two;

克雷格的相关答案中有更多解释:

PostgreSQL 9.2 row_to_json() with nested joins

db小提琴here旧sqlfiddle

【讨论】:

谢谢,但这会返回带有自动生成密钥的对象:"f1":"a","f2":"AA"。如何将f1 重命名为value_three @ehmicky:是的,如果您也想要列名,则需要将行转换为众所周知的复合类型。我再补充一点。 子选择,甚至 OP 的 cte 可能是为行的列名起别名的更方便的方法。 ***.com/questions/13227142/… 作为样式说明,我认为当我们将更新放在答案顶部并在原始注释下方注明它们适用的版本时,对于新人来说会更容易。只要您保持答案,它就永远是好的,随着时间的推移,对旧 PostgreSQL 的建议变得不那么有用了。 @Evan:我同意。我懒得更新我所有的旧答案。但既然这个无论如何都需要更新......

以上是关于在 SQL (Postgres) 中作为 JSON 对象数组返回的主要内容,如果未能解决你的问题,请参考以下文章

从 psycopg2 在 Postgres 中插入 dict 列表作为 json 数组

在postgres 9.5中插入包含json对象的数组作为行

使用 Pandas .to_sql 将 JSON 列写入 Postgres

将 json 作为 celery 任务的一部分插入 postgres

在 Postgres 9.4 中查找 JSON 数组中的最后一项

如何修改postgres数据库中的json字段