concat遇null即返回null,必须主动处理;推荐优先使用concat_ws自动跳过null并支持分隔符,或用ifnull/coalesce显式替换null为空字符串。

直接用 CONCAT() 拼多个字段最简单,但只要其中任意一个为 NULL,整条结果就变 NULL——这不是 bug,是设计行为,必须主动处理。
CONCAT 一碰 NULL 就失效,怎么防?
MySQL 的 CONCAT() 不跳过 NULL,也不报错,只默默返回 NULL。线上查不到数据却没报错,往往卡在这儿。
- 错误写法:
SELECT CONCAT(first_name, ' ', middle_name, ' ', last_name) FROM users;—— 只要middle_name是NULL,整行full_name就是NULL - 推荐方案:优先用
CONCAT_WS(),它自动忽略NULL参数,且自带分隔符逻辑 - 兜底方案:用
IFNULL(col, '')或COALESCE(col, '', 'N/A')显式替换,尤其当你要保留空格占位时(比如“张 三”,中间不能塌成“张三”)
CONCAT_WS 比 CONCAT 更适合多字段拼接
CONCAT_WS() 的第一个参数是分隔符,后面所有字段都按顺序拼,NULL 自动跳过,不中断流程。
- 安全写法:
SELECT CONCAT_WS(' ', first_name, middle_name, last_name) AS full_name FROM users;——middle_name为NULL时,等效于CONCAT(first_name, ' ', last_name) - 注意:分隔符本身不能是
NULL,否则整条结果仍是NULL;例如CONCAT_WS(NULL, 'a', 'b')返回NULL - 如果不需要分隔符(比如拼订单号:
'ORD' + id),仍可用CONCAT_WS('', 'ORD', id),但语义不如原生CONCAT()清晰
字段类型混用时的隐式转换风险
数字、日期传给 CONCAT() 会转字符串,但格式不可控——尤其是时间类字段受会话时区影响,数值类可能丢精度。
- 日期建议用
DATE_FORMAT(created_at, '%Y-%m-%d %H:%i')替代直接拼created_at - 数字建议显式转:
CAST(age AS CHAR)或CONVERT(price, CHAR),避免科学计数法或截断 - 拼接前检查字符集:
SELECT CHARSET(first_name), COLLATION(first_name),混合utf8mb4和latin1可能触发隐式降级甚至报错
WHERE 里用 CONCAT 基本等于放弃索引
在 WHERE 条件中对字段做 CONCAT()(比如 WHERE CONCAT(name, '_tmp') = 'xxx'),MySQL 无法使用 name 上的索引,全表扫描不可避免。
- 模糊查询场景(如
LIKE CONCAT('%', ? ,'%'))虽常见,但本质仍是函数包裹字段,无法走索引 - 高频查询建议改用生成列(generated column)+ 索引:
ALTER TABLE users ADD full_name VARCHAR(200) STORED AS (CONCAT_WS(' ', first_name, last_name)) INDEX; - 临时方案可考虑应用层拼接后查,或用全文索引替代
真正麻烦的不是语法,而是 NULL 处理和索引失效这两点——它们不会报错,只会让数据“消失”或查询“变慢”,上线前务必在真实数据上验证结果是否符合预期。











