[英]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
表| id | title |
|----|--------|
| 1 | title1 |
| 2 | title2 |
| 3 | title3 |
tags
表| id | question_id | name |
|----|-------------|------------|
| 1 | 1 | javascript |
| 2 | 1 | php |
| 3 | 1 | c# |
| 4 | 2 | mysql |
| 5 | 2 | php |
| 6 | 3 | c# |
comments
表| id | question_id | body |
|----|-------------|----------|
| 1 | 1 | comment1 |
| 2 | 1 | comment1 |
| 3 | 1 | comment2 |
| 4 | 3 | comment3 |
每個問題必須至少有一個標簽。 它也可以有 0 條或更多條評論。 對於一個問題,同一正文可以有兩條評論。
我想選擇所有問題,即他們的 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
,因為在一個問題上可以有多個評論同一個正文。
我知道這可能可以通過嵌套的select
來解決,但據我所知,它會對查詢的性能產生巨大的負面影響。
帶有數據庫架構和我的查詢的 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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.