如何在join字段中使用逗号分隔列表连接两个表

时间:2011-07-28 15:07:27

标签: mysql join csv

我有两个表,categoriesmovies

movies表中,我有一列categories。该列包含电影适合的类别。类别是以逗号分隔的ID。

以下是一个例子:

Table categories {
  -id-       -name-
  1          Action
  2          Comedy
  4          Drama
  5          Dance
}

Table movies {
  -id-       -categories-  (and some more columns ofc)
  1          2,4
  2          1,4
  4          3,5
}

现在回答实际问题:是否可以执行从movies表中排除categories列的查询,而是从categories表中选择匹配的类别并将它们返回到数组中?就像一个连接,但问题是有多个用逗号分隔的类别,是否有可能做某种正则表达式?

4 个答案:

答案 0 :(得分:18)

select
    m.id,
    group_concat(c.name)
from
    movies m
    join categories c on find_in_set(c.id, m.categories)
group by
    m.id

输出应该是这样的:

Table movies {
  -id-       -categories-
  1          Comedy,Drama
  2          Action,Drama
  4          Other,Dance
}

答案 1 :(得分:12)

在数据库字段中使用逗号分隔列表是一种反模式,应该不惜一切代价避免使用 因为它是一个PITA,用于在SQL中提取那些以逗号分隔的值。

相反,您应该添加一个单独的链接表来表示类别和电影之间的关系,如下所示:

Table categories
  id integer auto_increment primary key
  name varchar(255)

Table movies
  id integer auto_increment primary key
  name varchar(255)

Table movie_cat
  movie_id integer foreign key references movies.id
  cat_id integer foreign key references categories.id
  primary key (movie_id, cat_id)

现在你可以做到

SELECT m.name as movie_title, GROUP_CONCAT(c.name) AS categories FROM movies m
INNER JOIN movie_cat mc ON (mc.movie_id = m.id)
INNER JOIN categories c ON (c.id = mc.cat_id)
GROUP BY m.id

回到你的问题
您可以另外使用您的数据

SELECT m.name as movie_title
  , CONCAT(c1.name, if(c2.name IS NULL,'',', '), ifnull(c2.name,'')) as categories 
FROM movies m
LEFT JOIN categories c2 ON 
 (replace(substring(substring_index(m.categories, ',', 2),
  length(substring_index(m.categories, ',', 2 - 1)) + 1), ',', '') = c2.id)
INNER JOIN categories c1 ON 
 (replace(substring(substring_index(m.categories, ',', 1), 
  length(substring_index(m.categories, ',', 1 - 1)) + 1), ',', '') = c1.id)

请注意,最后一个查询仅在每部电影有2个或更少类别时才有效。

答案 2 :(得分:4)

布拉德是对的;规范化是解决方案。 存在规范化以解决这个问题。如果它的价值很高,那么你的MySQL书中应该很好地介绍它。


但是,如果你真的坚持,你可以通过与FIND_IN_SET交叉匹配伪造直接连接(这很方便地期望以逗号分隔的项目串)。

现在,MySQL无法返回“数组” - 这就是结果的集合 - 但它可以为您提供由管道(|)分隔的类别名称:

SELECT
       `m`.`id`,
       `m`.`name`,
       GROUP_CONCAT(`c`.`name` SEPARATOR "|") AS `cats`
  FROM
       `movies`     AS `m`,
       `categories` AS `c`
 WHERE
       FIND_IN_SET(`c`.`id`, `m`.`categories`) != 0
 GROUP BY
       `m`.`id`;

结果:

id  "name"     "cats"
---------------------------------------------------
1   "Movie 1"  "Comedy|Drama"
2   "Movie 2"  "Action|Drama"
4   "Movie 4"  "Dance"

答案 3 :(得分:-1)

这不是直接回答你的问题,但你在movies表中的内容真的很糟糕。

不是使用逗号组合categories,而应该做的是将每个类别放在不同的行上,例如:

Table movies {
  -id-       -categories-
  1          2
  1          4
  2          1
  2          4
  4          3
  4          5
}