简体   繁体   English

在 MySQL 中具有多个连接的 group_concat

[英]group_concat with multiple joins in MySQL

Database schema数据库模式

create table `questions` (
  `id` int not null auto_increment,
  `title` varchar(45) not null,
  primary key (`id`));

create table `tags` (
  `id` int not null auto_increment,
  `question_id` int not null,
  `name` varchar(45) not null,
  primary key (`id`));

create table `comments` (
  `id` int not null auto_increment,
  `question_id` int not null,
  `body` varchar(45) not null,
  primary key (`id`));

insert into questions (title) values
("title1"), ("title2"), ("title3");

insert into tags (question_id, name) values
(1, "javascript"), (1, "php"), (1, "c#"), (2, "mysql"), (2, "php"), (3, "c#");

insert into comments (question_id, body) values
(1, "comment1"), (1, "comment1"), (1, "comment2"), (3, "comment3");

That's how it looks visually:这就是它在视觉上的样子:

questions table questions

| id |  title |
|----|--------|
|  1 | title1 |
|  2 | title2 |
|  3 | title3 |

tags table tags

| id | question_id |       name |
|----|-------------|------------|
|  1 |           1 | javascript |
|  2 |           1 |        php |
|  3 |           1 |         c# |
|  4 |           2 |      mysql |
|  5 |           2 |        php |
|  6 |           3 |         c# |

comments table comments

| id | question_id |     body |
|----|-------------|----------|
|  1 |           1 | comment1 |
|  2 |           1 | comment1 |
|  3 |           1 | comment2 |
|  4 |           3 | comment3 |

Each question has to have at least one tag.每个问题必须至少有一个标签。 It can also have 0 or more comments.它也可以有 0 条或更多条评论。 There can be two comments with the same body on one question.对于一个问题,同一正文可以有两条评论。

Desired output期望输出

I want to select all questions, that is, their ids, titles, tags and comments.我想选择所有问题,即他们的 id、标题、标签和评论。

The output should look like that:输出应如下所示:

| id |  title |       tags        |          comments          |
|----|--------|-------------------|----------------------------|
|  1 | title1 | c#,php,javascript | comment1,comment1,comment2 |
|  2 | title2 | php,mysql         | (null)                     |
|  3 | title3 | c#                | comment3                   |

Attempts to solve the problem解决问题的尝试

I tried the following query:我尝试了以下查询:

select questions.id, questions.title,
  group_concat(tags.name), group_concat(comments.body)
from questions
join tags on questions.id = tags.question_id
left join comments on questions.id = comments.question_id
group by questions.id

Unfortunately, it doesn't work as expected.不幸的是,它没有按预期工作。 It produces the following output:它产生以下输出:

| id |  title | group_concat(distinct tags.name) |                                                      group_concat(comments.body) |
|----|--------|----------------------------------|----------------------------------------------------------------------------------|
|  1 | title1 |                c#,php,javascript | comment1,comment1,comment1,comment2,comment2,comment2,comment1,comment1,comment1 |
|  2 | title2 |                        php,mysql |                                                                           (null) |
|  3 | title3 |                               c# |                                                                         comment3 |

As you see, for the first question I get each comment three times, because there are three tags on this question.如您所见,对于第一个问题,每个评论我都会收到三遍,因为这个问题有三个标签。

Also, the comments are in the wrong order.另外,评论的顺序不对。 They should be in the same order as they were inserted, that is, comment1,comment1,comment2 , not comment1,comment2,comment1 .它们应该与插入的顺序相同,即comment1,comment1,comment2 ,而不是comment1,comment2,comment1

I can't use distinct for comments, as there can be multiple comments with the same body on one question.我不能在评论中使用distinct ,因为在一个问题上可以有多个评论同一个正文。

I know that this probably could be solved with nested select s, but as far as I know it would have a huge negative impact on the performance of the query.我知道这可能可以通过嵌套的select来解决,但据我所知,它会对查询的性能产生巨大的负面影响。

SQL Fiddle SQL小提琴

The SQL Fiddle with database schema and my query.带有数据库架构和我的查询的 SQL Fiddle

You need to first aggregate and apply GROUP_CONCAT and then join:您需要聚合并应用GROUP_CONCAT然后加入:

select questions.id, questions.title,
       tags.name, comments.body
from questions
join (
   select question_id, group_concat(tags.name) as name
   from tags
   group by question_id
) tags on questions.id = tags.question_id
left join (
   select question_id, group_concat(comments.body) as body
   from comments
   group by question_id
) comments on questions.id = comments.question_id

You can aggregate using a sub query before the join.您可以在连接之前使用子查询进行聚合。 As you appear to have unique tags then it would appear you can avoid using a sub query for the tags, and just join those as you currently do:-当您看起来有独特的标签时,您似乎可以避免对标签使用子查询,而只需像目前一样加入这些标签:-

SELECT questions.id, 
        questions.title,
        GROUP_CONCAT(tags.name ORDER BY tags.id), 
        comments.body
FROM questions
LEFT OUTER JOIN tags ON questions.id = tags.question_id
LEFT OUTER JOIN 
(
   SELECT question_id, 
            GROUP_CONCAT(comments.body ORDER BY id) as body
   FROM comments
   GROUP BY question_id
) comments ON questions.id = comments.question_id
GROUP BY questions.id, 
        questions.title,
        comments.body

Possible that you might get away with a correlated sub query.您可能会逃避相关的子查询。 This might be better it you have a very large number of questions, but will be limiting those you are interested in with a WHERE clause.如果您有大量问题,这可能会更好,但会使用 WHERE 子句限制您感兴趣的问题。 Down side is I am not sure if MySQL will be clever enough to perform the correlated sub query once for each question, rather than once for each occurrence of the question.不利的一面是我不确定 MySQL 是否足够聪明来为每个问题执行一次相关的子查询,而不是每次出现问题时执行一次。

SELECT questions.id, 
        questions.title,
        GROUP_CONCAT(tags.name ORDER BY tags.id), 
        (
            SELECT GROUP_CONCAT(comments.body ORDER BY id) 
            FROM comments
            WHERE questions.id = comments.question_id
            GROUP BY question_id
        ) AS body
FROM questions
LEFT OUTER JOIN tags ON questions.id = tags.question_id
GROUP BY questions.id, 
        questions.title,
        body

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM