来自三个表的 JOIN 和 GROUP_CONCAT 的意外结果

Posted

技术标签:

【中文标题】来自三个表的 JOIN 和 GROUP_CONCAT 的意外结果【英文标题】:Unexpected result from JOIN and GROUP_CONCAT with three tables 【发布时间】:2016-01-16 21:54:01 【问题描述】:

这里是架构和 sql 的链接:http://sqlfiddle.com/#!9/d99b6/8

架构:

create table movies (
  id int,
  movie_name varchar(20)
  );

create table genre (
  movie_id int,
  genre varchar(20)
  );

create table actors (
  movie_id int,
  actor_name varchar(20)
  );

insert into movies (id, movie_name)
  values
    (1, 'asdf');

insert into genre (movie_id, genre)
  values
    (1, 'Comedy'),
    (1, 'Thriller');

insert into actors (movie_id, actor_name) 
  values
    (1, 'actor1'),
    (1, 'actor2');

Sql:

select movies.id,
  movies.movie_name,
  group_concat(genre.genre separator ', ') as genre,
  group_concat(actors.actor_name separator ', ') as actors
from movies
inner join genre on genre.movie_id = movies.id
inner join actors on actors.movie_id = movies.id;

我想输出这个:

id    movie_name    genre               actors
1     asdf          Comedy, Thriller    actor1, actor2

但是换成这个:

id    movie_name    genre                                 actors
1     asdf          Comedy, Thriller, Comedy, Thriller    actor1, actor1, actor2, actor2

不知道如何解决这个问题,不胜感激。

【问题讨论】:

您应该在问题中包含示例数据以及查询。 SQL Fiddle 并不总是启动。 【参考方案1】:

你可以使用`distinct:

select m.id, m.movie_name,
       group_concat(distinct g.genre separator ', ') as genres,
       group_concat(distinct a.actor_name separator ', ') as actors
from movies m inner join
     genre g
     on g.movie_id = m.id inner join
     actors a
     on a.movie_id = m.id
group by m.id;

如果每部电影都有大量数据,那么distinct 会增加额外的开销。 joins 对每部电影的类型和演员进行笛卡尔积。您可以通过预聚合或使用相关子查询来处理:

select m.id, m.movie_name,
       (select group_concat(g.genre separator ', ')
        from genre g
        where g.movie_id = m.id 
       ) as genres,
       (select group_concat(a.actor_name separator ', ')
        from actors a
        where a.movie_id = m.id
       ) as actors
from movies m;

【讨论】:

【参考方案2】:

只需添加DISTINCT:

select movies.id,
  movies.movie_name,
  group_concat(DISTINCT genre.genre separator ', ') as genre,
  group_concat(DISTINCT actors.actor_name separator ', ') as actors
from movies
inner join genre on genre.movie_id = movies.id
inner join actors on actors.movie_id = movies.id;

SqlFiddleDemo

【讨论】:

以上是关于来自三个表的 JOIN 和 GROUP_CONCAT 的意外结果的主要内容,如果未能解决你的问题,请参考以下文章

来自 JOIN 表的 PIVOT

用join连接三个表的查询,该怎么写语句?

C# SqlDataAdapter 与来自多个数据库的表的 JOIN

C# SqlDataAdapter 与来自多个数据库的表的 JOIN

来自同一个表的多个 INNER JOIN

NNER JOIN连接两个表三个表五个表的SQL语句