我将array_to_json与array_agg结合使用,将PostgreSQL中的某些结果格式化为JSON。这适用于我想要返回查询的默认值的查询(所有列,未修改)。但我很难理解如何使用array_agg为查询创建一个JSON对象,我想在其中修改一些输出。
这是一个例子。假设我们有以下内容:
CREATE TABLE temp_user (
user_id serial PRIMARY KEY,
real_name text
);
CREATE TABLE temp_user_ip (
user_id integer,
ip_address text
);
INSERT INTO temp_user (user_id, real_name) VALUES (1, 'Elise'), (2, 'John'), (3, NULL);
INSERT INTO temp_user_ip (user_id, ip_address) VALUES (1, '10.0.0.4'), (2, '10.0.0.7'), (3, '10.0.0.9');
以下查询正常工作:
# SELECT array_to_json(array_agg(temp_user)) as users from temp_user;
users
-----------------------------------------------------------------------------------------------------
[{"user_id":1,"real_name":"Elise"},{"user_id":2,"real_name":"John"},{"user_id":3,"real_name":null}]
但是我要说我不喜欢用户3出现的空值。我宁愿看到字符串“用户从$ ip登录”。
我可以这样做:
# SELECT user_id, (CASE WHEN real_name IS NULL THEN (select 'User logged in from ' || ip_address FROM temp_user_ip WHERE user_id = temp_user.user_id) ELSE real_name END) as name from temp_user;
我得到以下结果:
user_id | name
---------+------------------------------
1 | Elise
2 | John
3 | User logged in from 10.0.0.9
哪个好。但我无法弄清楚如何像第一个例子那样将这些数据操作为JSON格式。
所需的输出当然如下:
[{"user_id":1,"name":"Elise"},{"user_id":2,"name":"John"},{"user_id":3,"name":"User logged in from 10.0.0.9"}]
以下不起作用:
# select array_to_json(array_agg ( (SELECT user_id, (CASE WHEN real_name IS NULL THEN (select 'User logged in from ' || ip_address FROM temp_user_ip WHERE user_id = temp_user.user_id) ELSE real_name END) as name from temp_user)));
ERROR: subquery must return only one column
我无法想出任何方法将数据转换为array_agg接受的格式。我甚至尝试创建一个与temp_user格式匹配的自定义类型,并尝试对类型构造函数进行array_agg调用,这会返回相同的错误。这个错误对我没有意义 - 如果子查询是聚合的,那么它返回多个列应该无关紧要。有什么建议?
答案 0 :(得分:18)
您可以将聚合调用与子查询分开,并使用row
构造函数生成复合数据:
SELECT
array_to_json(array_agg(row(t.*))) AS users
FROM
(
SELECT user_id,
CASE
WHEN real_name IS NULL
THEN (
SELECT 'User logged in from ' || ip_address
FROM temp_user_ip
WHERE user_id = temp_user.user_id
) ELSE real_name
END AS name
FROM temp_user
) t
;
您也可以在SQLFiddle上查看。
答案 1 :(得分:5)
这里只是一个更新,postgres现在有一个函数json_agg
,可用于array_to_json(array_agg( ... ))
的leiu但在某些情况下实际上表现更好,请参见此处:Array_agg in postgres selectively quotes
文档:https://www.postgresql.org/docs/9.5/static/functions-aggregate.html
这是修改过的查询:
SELECT
json_agg(row(t.*)) AS users
FROM
(
SELECT user_id,
CASE
WHEN real_name IS NULL
THEN (
SELECT 'User logged in from ' || ip_address
FROM temp_user_ip
WHERE user_id = temp_user.user_id
) ELSE real_name
END AS name
FROM temp_user
) t
;