Mysql与右表的IN和多个结果连接

Mysql与右表的IN和多个结果连接,mysql,join,left-join,outer-join,group-concat,Mysql,Join,Left Join,Outer Join,Group Concat,左表(简化)为: 右表为: id tag (ex:Sailing) 我想得到左表的结果,如下所示: row 1: name: Bob tags: Sailing,Snowboard,... 我最接近的是那里: SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags FROM (`left`) LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags) ORDER BY `name` as

左表(简化)为:

右表为:

id
tag (ex:Sailing)
我想得到左表的结果,如下所示:

row 1:
   name: Bob
   tags: Sailing,Snowboard,...
我最接近的是那里:

SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags
FROM (`left`)
LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags)
ORDER BY `name` asc
但由于组_CONCAT(),这只给了我一行。尽管如此,它给出了所有的结果,但只有逗号分隔列表中的第一个标记。我知道我很接近,但我在这件事上浪费了太多时间。谢谢你的帮助


我知道我可以创建第三个表left_right,其中包含行(id,left_id,right_id),以使其正常工作,但我希望避免这种情况。

首先,巴日梅加卡帕说的是正确的,还有更多。如果我正确理解了您描述的设置,那么您已经在浪费大量的空间(和性能)

您可以这样做:

CREATE TABLE pleft ( id integer, name varchar(20), tags integer );
CREATE TABLE pright ( id integer, tag varchar(20));

INSERT INTO pleft VALUES ( 1, 'Bob', 1 ), ( 9, 'Bob', 4 ), ( 15, 'Bob', 6 );
INSERT INTO pleft VALUES ( 2, 'Ann', 1 ), ( 3, 'Joe', 4 ), ( 4, 'Joe', 6 );

INSERT INTO pright VALUES ( 1, 'Sailing' ), ( 4, 'Snowboarding' ), ( 6, 'Skiing' );


SELECT pleft.name, GROUP_CONCAT(pright.tag)
    FROM pleft JOIN pright ON ( pleft.tags = pright.id )
    GROUP BY pleft.name ORDER BY pleft.name;

+------+-----------------------------+
| name | GROUP_CONCAT(pright.tag)    |
+------+-----------------------------+
| Ann  | Sailing                     |
| Bob  | Sailing,Skiing,Snowboarding |
| Joe  | Snowboarding,Skiing         |
+------+-----------------------------+
…但请注意,
pleft
表的每一行中的名称都是不必要的重复。理想情况下,您将有一个表对person进行建模:(id=1,name=“Bob”),一个表对标记进行建模(id=6,value=“ski”),还有一个表包含它们的关系。这将确保,例如,Bob决定使用“Robert”,您不必对整个tags表进行反Bob,而只需对涉及Bob的一行进行反Bob

更新

因此,
tags
是一个包含“1,4,6”的varchar字段。同样的逻辑也适用,但现在我们必须在重新整合之前分割这个领域。您不能在标记中使用类似“1”的内容,因为“11”将返回true(“1”毕竟包含在“11”中)。(这是被称为“乱穿马路”的SQL反模式:参见示例)

另一种方法是使用存储过程:请参阅


尝试按名称字段添加组,您应该能够选择所有名称及其标记的列表

SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags
FROM (`left`)
LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags)
GROUP BY `name`
ORDER BY `name` ASC;

标记
是整数字段吗?(您可以有几个具有不同标记的Bob行?)您无法真正避免这种情况,它将在将来变得更加混乱。如果您使用的是关系数据库,请尝试正确使用它们。您需要创建第三个表。tags是一个带有逗号分隔数字的VARCHAR。只有一排“鲍勃”和他的所有标签。我完全同意bažmegakapa的观点,特别是如果我们想在将来删除用户的标签,那么就更简单一些,但是我正在与之合作的另一位编写数据库插入代码的人对mysql不是很好,所以我试图让他更简单。哎哟。那么你想把标签从数字翻译成文本吗?我将编辑我的答案。不过,这会变得更复杂。是的,我知道,如果太麻烦的话,我会帮助我的队友创建第三个表。嗯,不起作用,使用GROUP__BY没有任何意义,GROUP_CONCAT查询无论如何只返回一行。哇,感谢Isemi的提醒,我不知道MySQL对乱穿马路反模式的行为是这样的,这在以后的开发中可能会有一些麻烦,谢谢!然而,对于一个包含数十万行的表来说,类似的解决方法将是缓慢的。如果没有更快的方法,我将创建第三个关系表
SELECT pleft.name, GROUP_CONCAT(pright.tag)
FROM pleft JOIN pright
    ON ( CONCAT(',',pleft.tags,',') LIKE CONCAT('%,',pright.id,',%' ))
GROUP BY pleft.name ORDER BY pleft.name;
CREATE TABLE pleft ( id integer, name varchar(20), tags varchar(20) );
INSERT INTO pleft VALUES ( 1, 'Bob', '1,4,6' ), ( 2, 'Jill', '4,1' );
SELECT pleft.name, GROUP_CONCAT(pright.tag)
    FROM pleft JOIN pright
        ON ( CONCAT(',',pleft.tags,',') LIKE CONCAT('%,',pright.id,',%' ))
    GROUP BY pleft.name ORDER BY pleft.name;
+------+-----------------------------+
| name | GROUP_CONCAT(pright.tag)    |
+------+-----------------------------+
| Bob  | Sailing,Snowboarding,Skiing |
| Jill | Sailing,Snowboarding        |
+------+-----------------------------+
SELECT `name`, GROUP_CONCAT(`right`.`tag`) AS tags
FROM (`left`)
LEFT OUTER JOIN `right` ON `right`.`id` IN(left.tags)
GROUP BY `name`
ORDER BY `name` ASC;