CONCAT用于同一行多列拼接,NULL会导致结果为NULL;UNION ALL用于纵向合并多行结果,不能横向拼列;GROUP_CONCAT才是多行变一行的正确函数,需注意长度限制和NULL处理。

CONCAT 和 UNION ALL 本身不组合使用来“把多列合并成一行”——这是常见误解。真正需要的场景,比如「把表中 col1、col2、col3 的值横向拼成一个字符串」,应直接用 CONCAT;而 UNION ALL 是纵向合并多行结果,不是横向拼字段。
如果你看到有人写 SELECT CONCAT(col1, col2) FROM t UNION ALL SELECT CONCAT(col3, col4) FROM t,那是在拼两批不同行的数据,不是把一整行的多个列“合并成一行展示”。
CONCAT 拼同一行的多个列:最常用也最容易出错
-
CONCAT接收多个参数,把它们按顺序连成一个字符串 - 任一参数为
NULL,整个结果就是NULL(不是跳过,也不是转成空字符串) - 中文、emoji 等多字节字符不会额外处理,但长度计算按字节算(
LENGTH()),和显示长度可能不一致
SELECT CONCAT(name, '(', department, ')') AS label FROM emp;- 若
department是NULL,整条结果是NULL - 改用
CONCAT_WS('-', name, department)更安全:自动跳过NULL,只用非空部分拼接 - 分隔符必须显式传入,不能省略;
CONCAT_WS('', a, b)等价于CONCAT(a, b)
UNION ALL 不是用来“合并列”的,但常被误用于跨行拼接
它本质是集合操作:把两个查询的结果堆叠成一列多行,列数和类型必须严格一致。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 常见错误写法:
SELECT col1 FROM t UNION ALL SELECT col2 FROM t→ 得到的是 col1 和 col2 各自所有值混在一起的一列,不是“每行把 col1+col2 拼起来” - 正确用途举例:汇总多个状态来源(如“待审核”+“已驳回”记录)再统一排序
- 如果硬要用它模拟“列转行”,得先用子查询或 CTE 把每列转成单列格式,再
UNION ALL,但性能差、可读性低,不推荐
GROUP_CONCAT 才是真正用来“多行变一行”的主力函数
这才是你实际想解决的问题背后该用的工具:
- 它在
GROUP BY下把分组内所有行的某列值拼成一个字符串 - 默认分隔符是英文逗号
,,可用SEPARATOR自定义 -
NULL值自动跳过(不会变成字符串"NULL") - 但默认最大长度是
1024字节,中文多时极易截断,必须查@@group_concat_max_len并用SET SESSION group_concat_max_len = ...调大
SELECT user_id, GROUP_CONCAT(tag ORDER BY created_at DESC SEPARATOR '; ') AS tags FROM user_tags GROUP BY user_id;
- 注意
ORDER BY和SEPARATOR必须写在GROUP_CONCAT()括号内,且顺序不能颠倒 - 如果原始数据里有逗号、引号等,
GROUP_CONCAT不做转义,导出后解析易崩,建议前端或应用层清洗,或提前用REPLACE(tag, ',', ',')处理
关键点就一个:别用 UNION ALL 想“把列拼成一行”,那是方向反了。CONCAT 拼本行字段,GROUP_CONCAT 拼本组多行字段——两者分工明确。最容易被忽略的是 NULL 导致整串变空,以及长度截断无声发生。

















