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

Return as array of JSON objects in SQL (Postgres)

我有下表MyTable

1
2
3
4
5
6
7
 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应单独存在。结果应该如下所示:

1
2
3
4
 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()

但我能做的最好的是:

1
2
3
4
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;

回报:

1
2
3
4
 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)查询?


Postgres 9.4或更新版本中的json_build_object()

1
2
3
4
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;

手册:

Builds a JSON object out of a variadic argument list. By convention,
the argument list consists of alternating keys and values.

对于任何版本(包括Postgres 9.3)

带有ROW表达式的row_to_json()将起到关键作用:

1
2
3
4
SELECT value_two
     , json_agg(row_to_json((value_three, value_four))) AS value_four
FROM   mytable
GROUP  BY value_two;

但会丢失原始列名称。对已注册行类型的强制转换可避免这种情况。(临时表的行类型也可用于特殊查询。)

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

或者使用嵌套select而不是ROW表达式。更详细,但没有类型转换:

1
2
3
4
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()与嵌套联接

db>小提琴在这里老SQL小提琴。