首先,bažmegakapa 说的是正确的,还有更多。如果我正确理解了您描述的设置,那么您已经在浪费大量空间(和性能)。
你可以这样做:
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
表格的每一行中是如何不必要地重复的。理想情况下,您将有一张表对人进行建模:(id=1, name="Bob"),一张表对标签进行建模 (id=6, value="Skiing") 和一张包含它们的关系的表。这将确保,例如,Bob 决定使用“Robert”,您不必对整个标签表进行 de-bob,而只需对涉及 Bob 的一行进行 de-bob。
更新
tags
持有“1,4,6”的 varchar 字段也是如此。同样的逻辑也适用,但现在我们必须在重新组合之前拆分字段。你不能使用像“1 in tags”这样的东西,因为“11”会返回true(“1”毕竟包含在“11”中)。(这是被称为“Jaywalking”的 SQL 反模式:参见例如https://groups.google.com/forum/?fromgroups=#!topic/django-users/5j4AmQE6nTk)
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;
另一种方法是使用存储过程:请参阅http://www.marcogoncalves.com/2011/03/mysql-split-column-string-into-rows/。
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 |
+------+-----------------------------+