【发布时间】:2016-09-22 18:13:21
【问题描述】:
数据库架构
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 个或多个 cmets。一个问题可以有两个 cmets 具有相同的身体。
期望的输出
我要选择所有问题,即他们的id、title、tags和cmets。
输出应该是这样的:
| 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 |
如你所见,对于第一个问题,我每条评论都得到了 3 次,因为这个问题上有三个标签。
此外,cmets 的顺序错误。它们应该与插入时的顺序相同,即comment1,comment1,comment2,而不是comment1,comment2,comment1。
我不能将distinct 用于 cmets,因为一个问题可能有多个 cmets 具有相同的正文。
我知道这可能可以通过嵌套selects 来解决,但据我所知,它会对查询的性能产生巨大的负面影响。
SQL 小提琴
The SQL Fiddle 带有数据库架构和我的查询。
【问题讨论】:
标签: mysql join group-concat