6

在我的 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"
    },
  },
  {...}
]

我尝试使用joinsarray_agg但无法获取该格式的数据。任何帮助将非常感激。注意:我也在使用 knex 来构建查询,但我认为 knex 不能在不求助于的情况下处理这样的事情knex.raw

4

2 回答 2

7

这应该这样做:

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;
于 2016-09-27T21:28:59.163 回答
2

回答更新的问题

不涉及json。只是普通的 Postgres 行和数组类型。并返回所有行和所有userscomments

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 构造函数应该是最简单和最快的。

但结果是一组匿名记录。你可能希望那样。我建议重新考虑你的方法。


回答原始问题

要返回显示为数据类型的结果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;

如果您应该更改表格布局,此查询将返回行并选取添加/删除的列。comments但是您必须users手动维护您对列的选择。

要获得显示的实际文本表示(数据类型text),您可以jsonb_pretty()在 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.

于 2016-09-28T01:20:56.593 回答