group_concat 在 MySQL 中有多个连接
group_concat with multiple joins in MySQL
数据库架构
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");
视觉上是这样的:
questions
table
| id | title |
|----|--------|
| 1 | title1 |
| 2 | title2 |
| 3 | title3 |
tags
table
| id | question_id | name |
|----|-------------|------------|
| 1 | 1 | javascript |
| 2 | 1 | php |
| 3 | 1 | c# |
| 4 | 2 | mysql |
| 5 | 2 | php |
| 6 | 3 | c# |
comments
table
| id | question_id | body |
|----|-------------|----------|
| 1 | 1 | comment1 |
| 2 | 1 | comment1 |
| 3 | 1 | comment2 |
| 4 | 3 | comment3 |
每个问题都必须至少有一个标签。它也可以有 0 个或多个评论。一个问题可以有两条相同的评论body
期望的输出
我要select所有问题,即他们的id、标题、标签和评论。
输出应如下所示:
| id | title | tags | comments |
|----|--------|-------------------|----------------------------|
| 1 | title1 | c#,php,javascript | comment1,comment1,comment2 |
| 2 | title2 | php,mysql | (null) |
| 3 | title3 | c# | comment3 |
尝试解决问题
我尝试了以下查询:
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
不幸的是,它没有按预期工作。它产生以下输出:
| 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 |
如您所见,对于第一个问题,每个评论我都得到了三次,因为这个问题上有三个标签。
另外,评论的顺序错了。它们的顺序应与插入时的顺序相同,即 comment1,comment1,comment2
,而不是 comment1,comment2,comment1
.
我不能用 distinct
评论,因为一个问题可以有多个相同 body 的评论。
我知道这可能可以通过嵌套 select
来解决,但据我所知这会对查询性能产生巨大的负面影响。
SQL Fiddle
The SQL Fiddle 使用数据库模式和我的查询。
您需要先聚合并应用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
您可以在联接之前使用子查询进行聚合。由于您似乎具有独特的标签,因此您似乎可以避免对标签使用子查询,而只需像您目前所做的那样加入这些标签:-
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
您可能会逃避相关子查询。如果您有大量问题,这可能会更好,但会使用 WHERE 子句限制您感兴趣的问题。不利的一面是我不确定 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
数据库架构
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");
视觉上是这样的:
questions
table
| id | title |
|----|--------|
| 1 | title1 |
| 2 | title2 |
| 3 | title3 |
tags
table
| id | question_id | name |
|----|-------------|------------|
| 1 | 1 | javascript |
| 2 | 1 | php |
| 3 | 1 | c# |
| 4 | 2 | mysql |
| 5 | 2 | php |
| 6 | 3 | c# |
comments
table
| id | question_id | body |
|----|-------------|----------|
| 1 | 1 | comment1 |
| 2 | 1 | comment1 |
| 3 | 1 | comment2 |
| 4 | 3 | comment3 |
每个问题都必须至少有一个标签。它也可以有 0 个或多个评论。一个问题可以有两条相同的评论body
期望的输出
我要select所有问题,即他们的id、标题、标签和评论。
输出应如下所示:
| id | title | tags | comments |
|----|--------|-------------------|----------------------------|
| 1 | title1 | c#,php,javascript | comment1,comment1,comment2 |
| 2 | title2 | php,mysql | (null) |
| 3 | title3 | c# | comment3 |
尝试解决问题
我尝试了以下查询:
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
不幸的是,它没有按预期工作。它产生以下输出:
| 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 |
如您所见,对于第一个问题,每个评论我都得到了三次,因为这个问题上有三个标签。
另外,评论的顺序错了。它们的顺序应与插入时的顺序相同,即 comment1,comment1,comment2
,而不是 comment1,comment2,comment1
.
我不能用 distinct
评论,因为一个问题可以有多个相同 body 的评论。
我知道这可能可以通过嵌套 select
来解决,但据我所知这会对查询性能产生巨大的负面影响。
SQL Fiddle
The SQL Fiddle 使用数据库模式和我的查询。
您需要先聚合并应用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
您可以在联接之前使用子查询进行聚合。由于您似乎具有独特的标签,因此您似乎可以避免对标签使用子查询,而只需像您目前所做的那样加入这些标签:-
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
您可能会逃避相关子查询。如果您有大量问题,这可能会更好,但会使用 WHERE 子句限制您感兴趣的问题。不利的一面是我不确定 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