Mysql 如何在联接字段中使用逗号分隔的列表联接两个表

Mysql 如何在联接字段中使用逗号分隔的列表联接两个表,mysql,join,csv,Mysql,Join,Csv,我有两个表,类别和电影 在movies表中,我有一列categories。该栏由电影所属的类别组成。类别是由逗号分隔的ID 下面是一个例子: Table categories { -id- -name- 1 Action 2 Comedy 4 Drama 5 Dance } Table movies { -id- -categories- (and some more co

我有两个表,
类别
电影

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表中选择匹配的类别并以数组形式返回它们?类似于连接,但问题是有多个类别用逗号分隔,是否可以执行某种正则表达式?

这并不是直接回答您的问题,但您在
movies
表中的内容非常糟糕

不要使用逗号组合
类别
,您应该做的是将每个类别放在单独的行上,例如:

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

布拉德是对的;正常化是解决方案。标准化的存在就是为了解决这个问题。如果值得的话,应该在你的MySQL书中很好地介绍它


但是,如果您真的坚持,您可以通过交叉匹配
FIND_IN_SET
(这很方便地需要逗号分隔的项目字符串)来伪造直接联接

现在,MySQL不能返回“数组”——这就是结果集的用途——但它可以给您以管道(
|
)分隔的类别名称:

结果:

id  "name"     "cats"
---------------------------------------------------
1   "Movie 1"  "Comedy|Drama"
2   "Movie 2"  "Action|Drama"
4   "Movie 4"  "Dance"
输出应如下所示:

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

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

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

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个或更少类别时有效。

为什么不规范化为三个表;电影,分类,电影分类?你说以数组形式返回它们是什么意思?你能改进问题标题吗?一系列技术并没有描述这个问题。这就是标签的含义。@Brad,这真是个好主意。我在创建数据库时没有想到这一点。这对我来说会容易得多。速度怎么样?如果我把它们分到第三张桌子上,处理器会不会更重?@Johan:我希望OP能获得自己动手的经验!不,这也很糟糕。电影类别关系应在单独的表中;您刚刚复制了
电影
中的所有“其他列”。这里至少有一个语法错误。我想如果你在电影m后面加上逗号,把上的改成一个
WHERE
(你没有使用写出的
连接
语法),那么你就会得到这个输出。但我看不出这个
“其他的”
是从哪里来的?@Tomalak这是个打字错误。我忘了添加
join
。我不喜欢在WHERE子句中写连接条件。另一个只是一个例子,它取决于
类别
表格。谢谢!我还没试过,但它看起来是合法的。不过我想我会让桌子正常化,从长远来看,这会让我更轻松。直到布拉德在评论中提出,我才想到这一点。不过非常感谢,无论如何总有一天这会派上用场的@Johan我有这个代码工作得很好,但我想做的不止2个。我需要更改什么?什么是
movie\u cat
id
?@LightnessRacesinOrbit,每个表都必须有一个主键。(或者遭受各种各样的障碍)。@Johan:这并不意味着你必须为它创建一个无意义的、任意递增的整数域。把主键放在
(电影id,猫id)
上大声叫喊!这部
movie\u cat
id
毫无意义。在这种情况下,我们如何加入多个表?@GaneshAher:这将是一件困难的事情,这也是为什么这是一个错误的工作工具的另一个原因!使用连接。
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)