我能将多个 MySQL 行连接成一个字段吗?

1480

使用MySQL,我可以做类似这样的事情:

SELECT hobbies FROM peoples_hobbies WHERE person_id = 5;

我的输出:

shopping
fishing
coding

但是我只想要一行一列:

预期输出:

shopping, fishing, coding

原因是我正在从多个表中选择多个值,在所有连接之后,我得到的行比我想要的要多很多。

我在MySQL文档上查找了一个函数,但似乎CONCATCONCAT_WS函数不接受结果集。

那么这里有没有人知道如何做到这一点呢?


10
我刚刚写了一个小演示,介绍如何使用group_concat,这可能对你有用:http://www.giombetti.com/2013/06/06/mysql-group_concat/。 - Marc Giombetti
这可能会对您有所帮助:https://www.w3resource.com/mysql/aggregate-functions-and-grouping/aggregate-functions-and-grouping-group_concat.php - Aasif khan
您可以使用XPath将行转换为列。 - Golden Lion
16个回答

2085
你可以使用 GROUP_CONCAT
SELECT person_id,
   GROUP_CONCAT(hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

正如Ludwig在他的评论中所述,你可以添加DISTINCT运算符以避免重复:

SELECT person_id,
   GROUP_CONCAT(DISTINCT hobbies SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

正如Jan在他们的评论中所述,您可以在使用ORDER BY进行implode之前对值进行排序:

SELECT person_id, 
       GROUP_CONCAT(hobbies ORDER BY hobbies ASC SEPARATOR ', ')
FROM peoples_hobbies
GROUP BY person_id;

正如Dag在他的评论中所述,结果存在1024字节的限制。要解决这个问题,在查询之前运行以下查询:

SET group_concat_max_len = 2048;

当然,您可以根据自己的需要更改2048。计算并分配该值:


SET group_concat_max_len = CAST(
                     (SELECT SUM(LENGTH(hobbies)) + COUNT(*) * LENGTH(', ')
                           FROM peoples_hobbies
                           GROUP BY person_id) AS UNSIGNED);

175
请注意结果列中的1024字节限制(请参见参数group_concat_max_len)。尽管这个参数可以被更改,但需要权衡考虑。 - Dag
87
加上DISTINCT参数后,你将不会得到任何重复的内容。 ... GROUP_CONCAT(DISTINCT hobbies) - Ludwig
即使在末尾省略了 GROUP BY person_id 子句,我仍然得到了相同的结果。 - Bikash Gyawali

126

如果您的MySQL版本(4.1)支持,可以看一下GROUP_CONCAT。有关更多详细信息,请参见文档

它的用法类似于:

  SELECT GROUP_CONCAT(hobbies SEPARATOR ', ') 
  FROM peoples_hobbies 
  WHERE person_id = 5 
  GROUP BY 'all';

15
我认为group by 'all'是不必要的(此外是不需要的),因为它会将字符串“all”赋给所有行,然后比较这些行之间的字符串。我说得对吗? - Krzysiek

93
我发现自己想要选择多个单独的行,而不是一组,并在某个字段上进行连接。
给定:
假设您有一个产品ID及其名称和价格的表:
+------------+--------------------+-------+
| product_id | name               | price |
+------------+--------------------+-------+
|         13 | Double Double      |     5 |
|         14 | Neapolitan Shake   |     2 |
|         15 | Animal Style Fries |     3 |
|         16 | Root Beer          |     2 |
|         17 | Lame T-Shirt       |    15 |
+------------+--------------------+-------+

然后你有一些花哨的ajax,将这些小狗列为复选框。

你饥肠辘辘的用户选择了13, 15, 16。今天她没有甜点...

寻找:

用纯mysql找到一种方法来总结用户的订单。

解决方案:

使用 IN子句GROUP_CONCAT

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary FROM product WHERE product_id IN (13, 15, 16);

输出结果为:

+------------------------------------------------+
| order_summary                                  |
+------------------------------------------------+
| Double Double + Animal Style Fries + Root Beer |
+------------------------------------------------+

额外解决方案:

如果你也想要总价格,那就加入SUM()函数:

mysql> SELECT GROUP_CONCAT(name SEPARATOR ' + ') AS order_summary, SUM(price) AS total FROM product WHERE product_id IN (13, 15, 16);
+------------------------------------------------+-------+
| order_summary                                  | total |
+------------------------------------------------+-------+
| Double Double + Animal Style Fries + Root Beer |    10 |
+------------------------------------------------+-------+

18
虽然这是一个好答案,但它听起来更像广告,而不是纯粹的回答。仍然是一个良好格式化的答案。 - THC
这与原帖的问题有什么关系? - Payel Senapati

41
您可以通过设置 group_concat_max_len 参数来更改 GROUP_CONCAT 值的最大长度。
请参阅MySQL文档中的详细信息。

31

28
在我的情况下,我有一排ID,必须将其转换为char类型,否则结果会被编码为二进制格式。

在我的情况下,我有一排ID,必须将其转换为char类型,否则结果会被编码为二进制格式:

SELECT CAST(GROUP_CONCAT(field SEPARATOR ',') AS CHAR) FROM table

20

我有一个更加复杂的查询,并发现我必须在外部查询中使用GROUP_CONCAT才能使其正常工作:

原始查询:

SELECT DISTINCT userID 
FROM event GROUP BY userID 
HAVING count(distinct(cohort))=2);

内爆:

SELECT GROUP_CONCAT(sub.userID SEPARATOR ', ') 
FROM (SELECT DISTINCT userID FROM event 
GROUP BY userID HAVING count(distinct(cohort))=2) as sub;

希望这能对某些人有所帮助。


19

使用MySQL (5.6.13)会话变量和赋值运算符,如下所示:

SELECT @logmsg := CONCAT_ws(',',@logmsg,items) FROM temp_SplitFields a;

那么你就可以获得

test1,test11

2
它比GROUP_CONCAT更快吗? - jave.web
2
我在PHPMyAdmin上使用MySQL服务器v5.6.17对_test_表中的_description_列(varchar(50))进行了测试,但它返回每个记录的BLOB字段:SELECT @logmsg:= CONCAT_ws(',',@logmsg,description)from test - Jan

14

如果有人想知道如何使用带子查询的GROUP_CONCAT,这里提供一个例子:

SELECT i.*,
(SELECT GROUP_CONCAT(userid) FROM favourites f WHERE f.itemid = i.id) AS idlist
FROM items i
WHERE i.id = $someid

因此,必须在子查询内使用GROUP_CONCAT,而不是将其包装起来。


10

试试这个:

DECLARE @Hobbies NVARCHAR(200) = ' '

SELECT @Hobbies = @Hobbies + hobbies + ',' FROM peoples_hobbies WHERE person_id = 5;

简而言之;

set @sql='';
set @result='';
set @separator=' union \r\n';
SELECT 
@sql:=concat('select ''',INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME  ,''' as col_name,',
INFORMATION_SCHEMA.COLUMNS.CHARACTER_MAXIMUM_LENGTH ,' as def_len ,' ,
'MAX(CHAR_LENGTH(',INFORMATION_SCHEMA.COLUMNS.COLUMN_NAME , '))as  max_char_len',
' FROM ',
INFORMATION_SCHEMA.COLUMNS.TABLE_NAME
) as sql_piece, if(@result:=if(@result='',@sql,concat(@result,@separator,@sql)),'','') as dummy
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE 
INFORMATION_SCHEMA.COLUMNS.DATA_TYPE like '%char%'
and INFORMATION_SCHEMA.COLUMNS.TABLE_SCHEMA='xxx' 
and INFORMATION_SCHEMA.COLUMNS.TABLE_NAME='yyy';
select @result;

2
这是我得到的:'未识别的语句类型。(在位置0附近的“DECLARE”)' - Istiaque Ahmed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接