首页 > 数据库 >MySQL concat_ws和group_concat的区别一文搞懂

MySQL concat_ws和group_concat的区别一文搞懂

来源:互联网 2026-07-26 08:35:02

MySQL中concat函数连接字符串时若任一参数为null则返回null;concat_ws可指定分隔符,分隔符为null时结果也为null;group_concat用于分组内多行拼接,支持去重、排序和自定义分隔符,但数值型需转为字符型。三者各有适用场景,需注意null值处理。

一、concat() 函数详解

在日常开发中,经常需要将多个字段拼接成一个字符串。MySQL 提供了三个函数来解决这类问题:concatconcat_wsgroup_concat。每个函数都有各自适用的场景,使用不当可能带来意料之外的问题。

concat() 的功能非常直接——将多个字符串连接成一个字符串。语法格式为 concat(str1, str2, …),返回结果为连接参数后生成的字符串。但有一个需要特别注意的地方:如果其中任何一个参数为 null,那么整个返回值都会变成 null

长期稳定更新的攒劲资源: >>>点此立即查看<<<

示例1:concat 基本用法

MySQL concat_ws和group_concat的区别一文搞懂

select CONCAT(id,name,email) as userinfo from users;

MySQL concat_ws和group_concat的区别一文搞懂

结果中有一行显示为 null,原因在于 users 表中该行的 email 值为 null。因此使用 concat 时,务必确认拼接的字段中不含 null,否则整条记录的结果都将失效。

示例2:concat 添加分隔符

上面的结果中,三个字段(id、name、email)直接拼接在一起,没有分隔符,可读性较差。加入逗号作为分隔符后效果会好很多:

select CONCAT(id,',',name,',',email) as userinfo from users;

MySQL concat_ws和group_concat的区别一文搞懂

二、concat_ws() 函数详解

每次使用 concat 都需要手动在每个字段之间添加逗号,字段数量较多时操作起来比较繁琐。为此 MySQL 提供了 concat_ws()——concat with separator,可以一次性指定分隔符,简化拼接过程。

语法格式:concat_ws(separator, str1, str2, …)。第一个参数即为分隔符。需要特别注意的是:分隔符不能为 null,如果设置为 null,结果会直接返回 null

示例:concat_ws 用法

使用 concat_ws() 将分隔符指定为逗号:

select CONCAT_WS(',',id,name,email) as userinfo from users;

MySQL concat_ws和group_concat的区别一文搞懂

至于为什么将分隔符设为 null 后结果全部变成 null,可以自行测试验证这一特性。

MySQL concat_ws和group_concat的区别一文搞懂

三、group_concat() 函数详解

前两个函数都是在单行内拼接字段,但实际工作中经常需要将多行数据按照某个分组归并到一起。例如,按姓名分组,将同一个人的所有 ID 拼接成一行。这时 group_concat() 就派上了用场。

先回顾一下基本规则:在使用 group by 的查询中,select 指定的字段要么包含在 group by 后面,要么包含在聚合函数中,否则会导致报错或结果不准确。

示例1:group_concat 基本用法

MySQL concat_ws和group_concat的区别一文搞懂

这个查询返回的是 name 相同的人中最小的 id。如果要查询 name 相同的人所有的 id,可以这样写:

MySQL concat_ws和group_concat的区别一文搞懂

但这样同一个名字会出现多次,数据冗余且不够直观。有没有更优雅的方式?——使用 group_concat()

group_concat() 的功能:将 group by 产生的同一分组中的值连接起来,返回一个字符串结果。

语法格式:

group_concat([DISTINCT] 要连接的字段  [Order BY ASC/DESC 排序字段]  [Separator '分隔符'])

通过 distinct 可以去除重复值;通过 order by 可以对结果排序;separator 用于指定分隔符,默认值为逗号。

示例2:group_concat 配合 group by

使用 group_concat() 配合 group by 显示相同名字的人的 id 号:

MySQL concat_ws和group_concat的区别一文搞懂

还可以将 id 从大到小排序,并使用 _ 作为分隔符:

MySQL concat_ws和group_concat的区别一文搞懂

上面只显示了 id,如果还想同时显示每个分组内的 email 呢?

MySQL concat_ws和group_concat的区别一文搞懂

完整语法示例

GROUP_CONCAT([DISTINCT] expr [,expr ...]             [ORDER BY {unsigned_integer | col_name | expr}                 [ASC | DESC] [,col_name ...]]             [SEPARATOR str_val])

测试数据准备

MySQL concat_ws和group_concat的区别一文搞懂

1. 查询所有学生的选课信息

SELECT    s.stu_id         AS  studentId,    s.stu_name       AS  studentName,    c.course_id      AS  courseId,    c.course_name    AS  studentCourseFROM    student sLEFT JOIN    stu_course scON    s.stu_id = sc.stu_idLEFT JOIN    course cON    sc.course_id = c.course_id

MySQL concat_ws和group_concat的区别一文搞懂

2. 使用 GROUP_CONCAT() 函数将结果分组归集

SELECT    s.stu_id       AS  studentId,    s.stu_name     AS  studentName,    GROUP_CONCAT(c.course_id)    AS  courseId,    GROUP_CONCAT(c.course_name)  AS  studentCourseFROM    student sLEFT JOIN    stu_course scON    s.stu_id = sc.stu_idLEFT JOIN    course cON    sc.course_id = c.course_idGROUP BY    studentId

MySQL concat_ws和group_concat的区别一文搞懂

需要注意的是:使用 GROUP_CONCAT 时,数值类型的数据会被转换为二进制 BLOB 类型,这可能导致显示异常。稳妥的做法是使用 CAST(expr AS type)CONVERT(expr, type) 将数值转成字符串:

SELECT    s.stu_id          AS  studentId,    s.stu_name     AS  studentName,    GROUP_CONCAT(CAST(c.course_id AS CHAR))     AS  courseId,    GROUP_CONCAT(c.course_name)  AS  studentCourseFROM    student sLEFT JOIN    stu_course scON    s.stu_id = sc.stu_idLEFT JOIN    course cON    sc.course_id = c.course_idGROUP BY    studentId

MySQL concat_ws和group_concat的区别一文搞懂

3. 对 courseId 按从小到大排序归集

可以在 GROUP_CONCAT() 中加入 ORDER BY

SELECT    s.stu_id          AS  studentId,    s.stu_name     AS  studentName,    GROUP_CONCAT(CAST(c.course_id AS CHAR) ORDER BY c.course_id) AS courseId,    GROUP_CONCAT(c.course_name)  AS  studentCourseFROM    student sLEFT JOIN    stu_course scON    s.stu_id = sc.stu_idLEFT JOIN    course cON    sc.course_id = c.course_idGROUP BY    studentId

MySQL concat_ws和group_concat的区别一文搞懂

这里有一个小细节需要注意:虽然 courseId 这一列已经按从小到大排序,但另一列 studentCourse 对应的数据并没有随之变动。这是 GROUP_CONCAT 的一个局限——各字段的排序是独立进行的,无法联动。如果哪位知道如何让另一列也跟着变动,欢迎分享。

4. 改变分隔符

GROUP_CONCAT 默认分隔符为逗号,使用 SEPARATOR 关键字可以替换为其他符号:

SELECT    s.stu_id       AS  studentId,    s.stu_name     AS  studentName,    GROUP_CONCAT(CAST(c.course_id AS CHAR) ORDER BY c.course_id SEPARATOR '/')    AS  courseId,    GROUP_CONCAT(c.course_name SEPARATOR '|')   AS  studentCourseFROM    student sLEFT JOIN    stu_course scON    s.stu_id = sc.stu_idLEFT JOIN    course cON    sc.course_id = c.course_idGROUP BY    studentId

MySQL concat_ws和group_concat的区别一文搞懂

数据库表结构

CREATE TABLE `users` (  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,  `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,  `email` varchar(255) CHARACTER SET utf8 DEFAULT NULL,  `email_verified_at` timestamp NULL DEFAULT NULL,  `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,  `remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,  `created_at` timestamp NULL DEFAULT NULL,  `updated_at` timestamp NULL DEFAULT NULL,  `deleted_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=50078 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('77', '', NULL, NULL, '', NULL, NULL, NULL, NULL);INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('5577', '', '55@qq.com', NULL, '', NULL, NULL, NULL, NULL);INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('50010', 'willem', '11@qq.com', NULL, '', NULL, NULL, NULL, '2022-04-07 14:03:11');INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('50012', 'wgchen', '22@qq.com', NULL, '', NULL, NULL, NULL, '2022-04-07 14:03:16');INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('50018', 'ycc', '33@qq.com', NULL, '', NULL, NULL, NULL, '2022-04-07 14:03:23');INSERT INTO `users` (`id`, `name`, `email`, `email_verified_at`, `password`, `remember_token`, `created_at`, `updated_at`, `deleted_at`) VALUES ('50077', '77', '', NULL, '', NULL, NULL, NULL, '2022-04-07 14:06:39');

实际应用案例

1. MySQL 中在字段前后添加字符

UPDATE optional_productSET cate_path = concat('|',cate_path,'|')

MySQL concat_ws和group_concat的区别一文搞懂

2. MySQL 中批量替换字段值:replace 函数

例如,表 mxd_goods 中字段 goods_pic 的值需要去掉前缀 goods/

MySQL concat_ws和group_concat的区别一文搞懂

执行以下语句:

update  mxd_goods set goods_pic= replace(goods_pic, 'goods/', '');

注意:务必加上 where id = 数字 条件,否则会进行全表修改,后果严重。

MySQL concat_ws和group_concat的区别一文搞懂

如何撤销修改?

UPDATE mxd_goodsSET goods_pic = REPLACE (goods_pic, 'g_', 'goods/g_')WHEREgoods_id = 1849;

3. substring(a,b,c) 字符串截取

substring(a,b,c):第一个参数 a 为被截取的字符串,第二个参数 b 为起始位置(从1开始计数),第三个参数 c 为截取长度。

示例:

SELECT  SUBSTRING("hello",2,2);

结果是从 'hello' 的第二个字符 'e' 开始截取两个字符,得到 "el"。

MySQL concat_ws和group_concat的区别一文搞懂

4. MySQL 删除最后一个字符

如果需要删除最后一个字符(例如移除多余的逗号),使用 SUBSTRING 只能显示修改后的结果,不会更新实际数据。如果需要更新列的值,可以使用 CONCAT(LEFT(…), '') 的方式:

UPDATE SET  = CONCAT(LEFT(, CHAR_LENGTH() -1), '')WHERE ;

也可以使用 SUBSTR 配合 CHAR_LENGTH 进行查询:

SELECTSUBSTR(title,1,CHAR_LENGTH(title) - 1)FROMhhir_crm_email_send_contentWHEREid = 14;

MySQL concat_ws和group_concat的区别一文搞懂

项目实战案例

SELECT`record`.`id`,`record`.`fund_name`,`record`.`report_type`,`record`.`number`,`record`.`year`,`record`.`quarter`,`record`.`notice_time`,`record`.`customer_sub_name`,`record`.`legal_subject_name`,`record`.`send_status`,`record`.`created_at`,`report_send`.`report_name`,`send_content`.`title` AS `email_title`,GROUP_CONCAT(`contact_link`.`contact_name`,concat('(', `contact_link`.`contact_email`, ');') SEPARATOR '') AS contactsFROM`hhir_crm_email_record` AS `record`LEFT JOIN `hhir_crm_email_report_send` AS `report_send` ON `report_send`.`email_record_id` = `record`.`id`AND `report_send`.`valid` = 1LEFT JOIN `hhir_crm_email_send_content` AS `send_content` ON `send_content`.`email_record_id` = `record`.`id`AND `send_content`.`valid` = 1LEFT JOIN `hhir_crm_email_contact_link` AS `contact_link` ON `contact_link`.`email_record_id` = `record`.`id`AND `contact_link`.`valid` = 1WHERE`record`.`valid` = 1GROUP BY `record`.`id`

MySQL concat_ws和group_concat的区别一文搞懂

SELECTid,GROUP_CONCAT(title,concat('(', cc_emails, ');') SEPARATOR '') AS email_titleFROMhhir_crm_email_send_contentWHEREid IN (12, 13)

MySQL concat_ws和group_concat的区别一文搞懂

MySQL concat_ws和group_concat的区别一文搞懂

总结

三个函数各有侧重:concat 适合简单拼接,但需要注意 null 值的影响;concat_ws 更加优雅,省去了重复书写分隔符的麻烦;group_concat 则是分组聚合的利器,特别适合处理一对多关系的数据归并。掌握这三个函数,日常的字符串处理工作会变得更加得心应手。

侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述

热游推荐

更多
湘ICP备14008430号-1 湘公网安备 43070302000280号
All Rights Reserved
本站为非盈利网站,不接受任何广告。本站所有软件,都由网友
上传,如有侵犯你的版权,请发邮件给xiayx666@163.com
抵制不良色情、反动、暴力游戏。注意自我保护,谨防受骗上当。
适度游戏益脑,沉迷游戏伤身。合理安排时间,享受健康生活。