3

示例:我有一些articlescomments我想得到这样的东西:

[{
   title: "Article 1",
   content: "Super long article goes here",
   comments: [
      { author: "Troll", message: "You suck, Sir!" }, 
      { author: "SpamBot", message: "http://superawesomething.com/"}
   ]
},{
   title: "Article 2",
   content: "Another long article goes here",
   comments: [ ... ]
}]

现在我看到两个解决方案:

  1. 首先获取文章,然后是带有某些IN条件的第二个查询中的评论,最后将评论添加到相应的文章中。
  2. 好旧的加入。一方面,我仍然需要大量摆弄数据才能进入我想要的结构。但除此之外,我有点担心,因为articles.content每条评论都会传输有效载荷 - 除非有办法进行我不知道的加入。

我希望我的 SQL 文盲让我错过了简单的解决方案。

4

4 回答 4

6

您可以使用聚合和/或子查询来执行此操作。就像是:

select title, content, json_agg(comments.author, comments.message) as comments
from articles 
join comments on articles.article_id = comments.article_id
group by article_id;

如果您需要将其聚合到一个字符串/json/something 中 - 只需将其包装到另一个聚合查询中,如下所示:

select json_agg(sub)
from (
  select title, content, json_agg(comments.author, comments.message) as comments
  from articles 
  join comments on articles.article_id = comments.article_id
  group by article_id) sub;

这是一个 Postgres 查询。对Mysql没有经验。

于 2013-09-10T19:58:13.613 回答
1

这是一个 MySQL 解决方案:

SELECT CONCAT( '[ { '
              ,GROUP_CONCAT( CONCAT( 'title: "', REPLACE( a.title, '"', '\"' ), '"'
                                    ,', contents: "', REPLACE( a.content, '"', '\"' ), '"'
                                    ,', comments: ', a.comments
                                   )
                             SEPARATOR ' }, { '
                           )
              ,' } ]'
             )
  FROM (SELECT a1.title
              ,a1.content
              ,CONCAT( '[ { '
                      ,GROUP_CONCAT( CONCAT( 'author: "', REPLACE( c.author, '"', '\"' ), '"'
                                            ,', message: "', REPLACE( c.message, '"', '\"' ), '"'
                                           )
                                     SEPARATOR ' }, { '
                                   )
                      ,' } ]'
                     ) as comments
          FROM articles a1
          LEFT OUTER
          JOIN comments c
            ON c.articleId = a1.articleId
         GROUP BY a1.title, a1.content
       ) a
;

随着字符串变大,这将需要一些调整。最好每篇文章返回一行:

SELECT a1.title
      ,a1.content
      ,CONCAT( '[ { '
              ,GROUP_CONCAT( CONCAT( 'author: "', REPLACE( c.author, '"', '\"' ), '"'
                                    ,', message: "', REPLACE( c.message, '"', '\"' ), '"'
                                   )
                             SEPARATOR ' }, { '
                           )
              ,' } ]'
             ) as comments
  FROM articles a1
  LEFT OUTER
  JOIN comments c
    ON c.articleId = a1.articleId
 GROUP BY a1.title, a1.content

SQLFiddle:http ://sqlfiddle.com/#!2/5edcd/13

于 2013-09-13T19:30:03.497 回答
0

如果两个查询都在同一个事务中完成,则第一种方法是正确的。它基本上用服务器端的 CPU 时间(用于昂贵的第二次查询)换取客户端的一些 CPU 时间和介于两者之间的网络流量。

虽然第二种方法起初在网络流量方面似乎代价高昂,但一些在线协议支持以有效的方式引用相同值的列。在这种情况下,不会为每一行传输由于连接而重复的列值。您应该检查实际产生了多少流量,开销可能没有看起来那么大。
在客户端,您可以使用的主键将所有内容存储articles在类似 hashmap 的对象中。article在接收行时,您将注释添加到列表中,每个列表都由该键索引。这可以通过根据article的主键在服务器端对行进行排序来提高效率,使您能够在客户端使用自然排序的列表列表。与第一种方法相比,构建这种结构是 CPU 时间的权衡。
我的结论:使用JOIN.

于 2013-09-10T20:00:12.507 回答
0

PostgreSQL 的 json_agg 函数的等效函数已在 MySQL 的下一个版本的议程上。

这将非常有帮助。

您可以在以下位置进行检查(有一个提示可以与当前版本实现相同的结果):

MySQL 8.0 Labs:JSON 聚合函数(后续)

于 2017-11-23T23:45:13.523 回答