前言
在MySQL
中,你可以通过GROUP_CONCAT
函数获取一个将所有字符串串联在一起的新字符串,其语法定义如下:
GROUP_CONCAT([DISTINCT] expr [,expr ...]
[ORDER BY {unsigned_integer | col_name | expr}
[ASC | DESC] [,col_name ...]]
[SEPARATOR str_val])
该函数的作用经常可以用于将多列数据合并为一列返回,方便客户端拿到后直接使用。
演示示例
我们可以简单的演示一下其使用效果。
准备一张数据表。
执行如下查询语句:select name,GROUP_CONCAT(age) from t1 GROUP BY name;
返回结果:
高级语法
从语法定义上来,GROUP_CONCAT
还在拼接字符串时还能提供一些额外的能力,比如拼接后的字符串可以排序、去重、按指定分隔符拼接等。
比如这样一个SQL语句就指定了拼接的字符串要按照'&'
分割,并且要对age
去重后按照正序返回:select name,GROUP_CONCAT(DISTINCT age order by age asc SEPARATOR '&') from t1 GROUP BY name;
线上遇到的问题
GROUP_CONCAT
实际上还有一个允许返回的最大结果长度的参数:group_concat_max_len
,且默认值为1024
字节,也就是说如果拼接后的字符串超过这个长度则会被截断。
执行这个命令,表示将最大结果长度修改为1
个字节:SET SESSION group_concat_max_len = 1;
此时再查询时,结果就被截断返回了:
这实际上是个非常严重的问题,拼接后的字符串最后一位是1
,客户端并不知情,会直接把1
也当做目标结果来处理。
我们在实际业务应用中就由于没有考虑到这个问题,最终导致线上运营出现故障。
解决方式
解决方式自然很简单,要么调大group_concat_max_len
参数值,要么客户端控制好一次性拼接的大小。
不过,需要注意的是group_concat_max_len
尽管可以设置的很高,但最终其最大返回长度还受max_allowed_packet
参数限制,其默认值为4M
。
额外扩展
类似的拼接函数,还有CONCAT_WS(separator,str1,str2,...)
、CONCAT(str1,str2,...)
、JSON_ARRAYAGG(col_or_expr)
、JSON_OBJECTAGG(key, value)
,在特定场景中,都是比较好用的拼接函数。
CONCAT_WS(separator,str1,str2,...)
演示:
mysql> SELECT CONCAT_WS(',','First name','Second name','Last Name');
-> 'First name,Second name,Last Name'
mysql> SELECT CONCAT_WS(',','First name',NULL,'Last Name');
-> 'First name,Last Name'
CONCAT(str1,str2,...)
演示:
mysql> SELECT CONCAT('My', 'S', 'QL');
-> 'MySQL'
mysql> SELECT CONCAT('My', NULL, 'QL');
-> NULL
mysql> SELECT CONCAT(14.3);
-> '14.3'
JSON_ARRAYAGG(col_or_expr)
演示:
mysql> SELECT o_id, attribute, value FROM t3;
+------+-----------+-------+
| o_id | attribute | value |
+------+-----------+-------+
| 2 | color | red | | 2 | fabric | silk |
| 3 | color | green | | 3 | shape | square|
+------+-----------+-------+
4 rows in set (0.00 sec)
mysql> SELECT o_id, JSON_ARRAYAGG(attribute) AS attributes
-> FROM t3 GROUP BY o_id;
+------+---------------------+
| o_id | attributes |
+------+---------------------+
| 2 | ["color", "fabric"] |
| 3 | ["color", "shape"] |
+------+---------------------+
2 rows in set (0.00 sec)
JSON_OBJECTAGG(key, value)
演示:
mysql> SELECT o_id, attribute, value FROM t3;
+------+-----------+-------+
| o_id | attribute | value |
+------+-----------+-------+
| 2 | color | red | | 2 | fabric | silk |
| 3 | color | green | | 3 | shape | square|
+------+-----------+-------+
4 rows in set (0.00 sec)
mysql> SELECT o_id, JSON_OBJECTAGG(attribute, value)
-> FROM t3 GROUP BY o_id;
+------+---------------------------------------+
| o_id | JSON_OBJECTAGG(attribute, value)
| +------+---------------------------------------+
| 2 | {"color": "red", "fabric": "silk"} |
| 3 | {"color": "green", "shape": "square"}
| +------+---------------------------------------+
2 rows in set (0.00 sec)
需要注意,因为JSON类型不允许有重复键出现,所以,如果attribute值重复,则会按照最后一个attribute值返回。