返回同一行的多个列作为对象的 JSON 数组

问题描述 投票:0回答:3

我有下表

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_three, value_four }
分组的对象数组
value_two
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) 查询?

sql arrays json postgresql aggregate-functions
3个回答
90
投票

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;

说明书:

从可变参数列表中构建一个 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;

Craig 相关回答中的更多解释:

db<>小提琴这里
sqlfiddle


0
投票

to_jsonarray_agg复合类型

begin;
create table  mytable(
id bigint, value_two text, value_three text, value_four  text);
insert into mytable(id,value_two, value_three,value_four)
values
 ( 1, 'a',       'A',           'AA'),
  (2, 'a'    ,     'A2'  ,       'AA2'),
  (3, 'b'  ,       'A3',         'AA3'),
 ( 4, 'a'   ,      'A4',          'AA4'),
  (5, 'b' ,        'A5',          'AA5');
commit;
create type mytable_type as (value_three text, value_four text);

select value_two,
       to_json( array_agg(row(value_three,value_four)::mytable_type))
from mytable
group by 1;

0
投票

使用

jsonb_agg
to_jsonb

SELECT
    value_two,
    jsonb_agg(to_jsonb (t.*) - '{id,value_two}'::text[]) AS data
FROM
    mytable t
GROUP BY
    1
ORDER BY
    1;

基于手册参考

jsonb - 文本 [] → jsonb

从左操作数中删除所有匹配的键或数组元素。

© www.soinside.com 2019 - 2024. All rights reserved.