SQL 数组聚合和连接
SQL array agg and joins
在我的 Postgres 数据库中,我有 3 个表。一个用于 users
,一个用于 comments
,一个用于映射两个 user_comment_map
。表格如下所示:
users
| id | name | age |
|----|------|-----|
| 1 | user | 20 |
comments
| id | mood | subject | content | created_at |
|----|-------|---------|-----------------|--------------------------|
| 1 | happy | funny | here is content | Tue Sep 27 2016 13:44:19 |
| 2 | silly | cool | more content | Tue Sep 27 2016 14:44:19 |
user_comment_map
| id | user_id | comment_id |
|----|---------|------------|
| 1 | 1| 1|
| 2 | 1| 2|
我正在尝试编写一个 SQL 查询,结果为以下对象:
[{
id: 1,
name: "user",
age: 20,
comments: [
{
id: 1,
mood: "happy",
subject: "silly",
content: "here is content",
created_at: "Tue Sep 27 2016 13:44:19"
},
{
id: 2,
mood: "silly",
subject: "cool",
content: "more content",
created_at: "Tue Sep 27 2016 14:44:19"
},
},
{...}
]
我尝试使用 joins
和 array_agg
,但我无法获取该格式的数据。任何帮助将非常感激。注意:我也在使用 knex 来构建查询,但我不认为 knex 可以在不求助于 knex.raw
的情况下处理这样的事情
应该这样做:
SELECT
json_build_object(
'id',id,
'name',name,
'comments',(
SELECT json_agg(json_build_object(
'id', comments.id,
'mood', comments.mood,
'subject', comments.subject,
'content', comments.content,
'created_at', comments.created_at
))
FROM user_comment_map JOIN comments ON comment_id=comments.id
WHERE user_id=users.id
)
)
FROM users
WHERE id=1;
更新问题的答案
不涉及json
。只是普通的 Postgres 行和数组类型。并且 return 所有行的所有列来自 users
和 comments
:
SELECT ARRAY(
SELECT t
FROM (
SELECT u.*
, (SELECT array_agg(c)
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id
) AS comments
FROM users u
) t
);
在子查询上使用 ARRAY constructor 应该是最简单和最快的。
但结果是一组匿名记录。您可能不想要那个。我建议重新考虑你的方法。
原问题的答案
到return结果显示为数据类型json
(省略users.age
),to_json()
上的别名子查询应该是最简单和最快的。
适用于 Postgres 9.2 或更高版本:
SELECT to_json(t)
FROM (
SELECT u.id, u.name -- manual selection from from table users
, (SELECT json_agg(c) -- use table alias of comments to wrap whole row
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id
) AS comments
FROM users u
WHERE u.id = 1
) t;
此查询 returns whole 行来自 comments
并在您应该更改 table 布局时选择添加/删除的列.但是您必须手动维护从 users
中选择的列。
要显示实际文本表示(数据类型text
),您可以在 Postgres 9.5 或更高版本:
SELECT jsonb_pretty(to_jsonb(t))
FROM (
SELECT u.id, u.name
, (SELECT jsonb_agg(c)
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id) AS comments
FROM users u
WHERE u.id = 1
) t;
我在这里使用 jsonb
函数,因为 json_pretty()
只需要 jsonb
。
在我的 Postgres 数据库中,我有 3 个表。一个用于 users
,一个用于 comments
,一个用于映射两个 user_comment_map
。表格如下所示:
users
| id | name | age |
|----|------|-----|
| 1 | user | 20 |
comments
| id | mood | subject | content | created_at |
|----|-------|---------|-----------------|--------------------------|
| 1 | happy | funny | here is content | Tue Sep 27 2016 13:44:19 |
| 2 | silly | cool | more content | Tue Sep 27 2016 14:44:19 |
user_comment_map
| id | user_id | comment_id |
|----|---------|------------|
| 1 | 1| 1|
| 2 | 1| 2|
我正在尝试编写一个 SQL 查询,结果为以下对象:
[{
id: 1,
name: "user",
age: 20,
comments: [
{
id: 1,
mood: "happy",
subject: "silly",
content: "here is content",
created_at: "Tue Sep 27 2016 13:44:19"
},
{
id: 2,
mood: "silly",
subject: "cool",
content: "more content",
created_at: "Tue Sep 27 2016 14:44:19"
},
},
{...}
]
我尝试使用 joins
和 array_agg
,但我无法获取该格式的数据。任何帮助将非常感激。注意:我也在使用 knex 来构建查询,但我不认为 knex 可以在不求助于 knex.raw
应该这样做:
SELECT
json_build_object(
'id',id,
'name',name,
'comments',(
SELECT json_agg(json_build_object(
'id', comments.id,
'mood', comments.mood,
'subject', comments.subject,
'content', comments.content,
'created_at', comments.created_at
))
FROM user_comment_map JOIN comments ON comment_id=comments.id
WHERE user_id=users.id
)
)
FROM users
WHERE id=1;
更新问题的答案
不涉及json
。只是普通的 Postgres 行和数组类型。并且 return 所有行的所有列来自 users
和 comments
:
SELECT ARRAY(
SELECT t
FROM (
SELECT u.*
, (SELECT array_agg(c)
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id
) AS comments
FROM users u
) t
);
在子查询上使用 ARRAY constructor 应该是最简单和最快的。
但结果是一组匿名记录。您可能不想要那个。我建议重新考虑你的方法。
原问题的答案
到return结果显示为数据类型json
(省略users.age
),to_json()
上的别名子查询应该是最简单和最快的。
适用于 Postgres 9.2 或更高版本:
SELECT to_json(t)
FROM (
SELECT u.id, u.name -- manual selection from from table users
, (SELECT json_agg(c) -- use table alias of comments to wrap whole row
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id
) AS comments
FROM users u
WHERE u.id = 1
) t;
此查询 returns whole 行来自 comments
并在您应该更改 table 布局时选择添加/删除的列.但是您必须手动维护从 users
中选择的列。
要显示实际文本表示(数据类型text
),您可以在 Postgres 9.5 或更高版本:
SELECT jsonb_pretty(to_jsonb(t))
FROM (
SELECT u.id, u.name
, (SELECT jsonb_agg(c)
FROM user_comment_map uc
JOIN comments c ON uc.comment_id = c.id
WHERE uc.user_id = u.id) AS comments
FROM users u
WHERE u.id = 1
) t;
我在这里使用 jsonb
函数,因为 json_pretty()
只需要 jsonb
。