PostgreSQL返回结果集为JSON数组?
我希望PostgreSQL将查询结果作为一个JSON数组返回。给定PostgreSQL返回结果集为JSON数组?,json,postgresql,Json,Postgresql,我希望PostgreSQL将查询结果作为一个JSON数组返回。给定 create table t (a int primary key, b text); insert into t values (1, 'value1'); insert into t values (2, 'value2'); insert into t values (3, 'value3'); 我想要类似的 [{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"
create table t (a int primary key, b text);
insert into t values (1, 'value1');
insert into t values (2, 'value2');
insert into t values (3, 'value3');
我想要类似的
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
或
(实际上,两者都知道会更有用)。我试过一些东西,比如
select row_to_json(row) from (select * from t) row;
select array_agg(row) from (select * from t) row;
select array_to_string(array_agg(row), '') from (select * from t) row;
我觉得我很接近,但不是真的。我是否应该查看除以下内容之外的其他文档
顺便说一下,我对我的想法不太确定。这是一个常见的设计决策吗?我的想法是,当然,我可以将上述3个查询中的第一个查询的结果(例如)在应用程序中稍微处理一下,然后再将其提供给客户机,但如果PostgreSQL可以直接创建最终的JSON对象,则会更简单,因为我仍然没有在我的应用程序中包含任何对JSON库的依赖 TL;博士
对于对象的JSON数组,以及
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
对于数组的JSON对象
对象列表
本节介绍如何生成对象的JSON数组,并将每一行转换为单个对象。结果如下所示:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.3及以上
json\u agg
函数会立即生成此结果。它会自动找出如何将输入转换为JSON并将其聚合为数组
SELECT json_agg(t) FROM t
没有jsonb
(在9.4中引入)版本的json\u agg
。您可以将行聚合为一个数组,然后将其转换为:
SELECT to_jsonb(array_agg(t)) FROM t
或者将json\u agg
与强制转换组合:
SELECT json_agg(t)::jsonb FROM t
我的测试表明,首先将它们聚合到一个数组中要快一点。我怀疑这是因为强制转换必须解析整个JSON结果
9.2
9.2没有json_agg
或to_json
函数,因此您需要使用较旧的数组to_json
:
SELECT array_to_json(array_agg(t)) FROM t
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
您可以选择在查询中包含一个row\u to\u json
调用:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
这会将每一行转换为JSON对象,将JSON对象聚合为数组,然后将数组转换为JSON数组
我看不出两者之间有任何显著的性能差异
清单的对象
本节介绍如何生成JSON对象,每个键都是表中的一列,每个值都是该列值的数组。结果如下所示:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5及以上
我们可以利用json\u build\u对象
函数:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
您还可以聚合列,创建一行,然后将其转换为对象:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
请注意,为确保对象具有所需的名称,绝对需要对数组进行别名处理
哪一个更清楚是意见的问题。如果使用json\u build\u object
函数,我强烈建议在一行中放置一个键/值对,以提高可读性
您也可以使用array\u agg
代替json\u agg
,但我的测试表明json\u agg
稍微快一点
没有json\u build\u对象
函数的jsonb
版本。您可以聚合为一行并转换:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
与其他针对此类结果的查询不同,array\u agg
在使用to\u jsonb
时似乎要快一点。我怀疑这是由于解析和验证JSON\u agg
的JSON结果的开销造成的
也可以使用显式强制转换:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
根据我的测试,to_jsonb
版本允许您避免强制转换,并且速度更快;同样,我怀疑这是由于解析和验证结果的开销造成的
9.4和9.3
json\u build\u object
函数是9.5中新增的,因此您必须在以前的版本中聚合并转换为对象:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
或
取决于您是想要json
还是jsonb
(9.3没有jsonb
)
9.2
在9.2中,甚至不存在to_json
。您必须使用行到行json
:
SELECT array_to_json(array_agg(t)) FROM t
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
文档
在中查找JSON函数的文档
json\u agg
在页面上
设计
如果性能很重要,请确保根据自己的模式和数据对查询进行基准测试,而不是信任我的测试
它是否是一个好的设计实际上取决于您的具体应用。在可维护性方面,我看不出有什么特别的问题。它简化了你的应用程序代码,意味着在应用程序的这一部分需要维护的内容更少。如果PG能够提供您所需的现成结果,那么我能想到的不使用它的唯一原因就是性能方面的考虑。不要重新发明轮子和一切
空值
聚合函数在零行上运行时通常返回NULL
。如果这是一种可能性,您可能希望使用COALESCE
来避免它们。举几个例子:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
或
如果您希望从表中选择字段并聚合为数组,也可以将其归功于
SELECT json_agg(json_build_object('data_a',a,
'data_b',b,
)) from t;
结果会来的
[{'data_a':1,'data_b':'value1'}
{'data_a':2,'data_b':'value2'}]
PG 9.4现已在beta 1版本中提供,它改进了对JSON的支持,包括二进制I/O。如果您在开发机器上,您可能想查看一下。@Patrick:谢谢,它看起来确实像JSON_object()是9.4中的一个新函数,我会尝试从t中选择JSON_对象(array_agg(t.a),array_agg(t.b)),如果我有它,谢谢你的回答。您启发我找到第二个问题的答案,从t中选择row_to_json(row(array_agg(t.a),array_agg(t.b)),尽管结果以“f1”和“f2”作为标签,而不是a和b。@engineerX我扩展了我的答案。在某些情况下,当内部选择(从t)时,返回NULL而不是空json数组是不可取的返回零行。这是由聚合函数在选择无行时总是返回NULL引起的,可通过coalesce解决:array_to_json(coalesce(array_agg(t),array[]::record[])。您可以使用
to_json
而不是row_to_json
和array_to_json
“没有jsonb(在9.4中引入