CONCAT不会将NULL视为空字符串,遇NULL直接返回NULL;CONCAT_WS仅跳过值为NULL的字段,分隔符必须非NULL且不可省略。

CONCAT 会把 NULL 当成空字符串吗?
不会。CONCAT 遇到任意一个参数为 NULL,整个结果直接返回 NULL——这是它最常踩的坑。
比如:CONCAT('a', NULL, 'c') 结果是 NULL,不是 'ac'。这在拼接用户姓名、地址字段时特别危险,因为数据库里很多字段允许为空。
- 适用场景:你**确定所有字段非 NULL**,或已用
IFNULL/COALESCE预处理过 - 想绕过 NULL 中断,得手动兜底:
CONCAT(IFNULL(first_name, ''), ' ', IFNULL(last_name, '')) - 注意:MySQL 8.0+ 支持
CONCAT的严格模式,但默认仍按老行为走
CONCAT_WS 的分隔符真的“自动跳过 NULL”吗?
只跳过**值为 NULL 的字段**,不跳过分隔符本身;而且第一个参数必须是分隔符,不能省略或传 NULL。
例如:CONCAT_WS('-', 'a', NULL, 'c') 返回 'a-c';但 CONCAT_WS(NULL, 'a', 'b') 会报错:Incorrect arguments to CONCAT_WS。
- 适用场景:拼接可变长度字段(如标签列表、多级地址),且希望忽略空值
- 分隔符是强制参数,不能缺;传空字符串
''是合法的,结果里就不会有分隔符 - 性能上比多次嵌套
IFNULL+CONCAT略优,因为内置逻辑更轻量
两个函数在排序和索引里的表现一样吗?
都不支持函数索引(除非显式创建函数索引),但影响方式不同。
CONCAT(a,b) 的结果无法命中 a 或 b 单独的索引;CONCAT_WS('-', a, b) 同样不可下推,且因内部处理多一步判断,执行计划里可能显示额外的 Using temporary。
- 如果要按拼接结果查,优先考虑生成列(Generated Column)+ 索引:
ALTER TABLE t ADD COLUMN full_name VARCHAR(100) STORED AS (CONCAT_WS(' ', first_name, last_name)) - WHERE 条件里别写
WHERE CONCAT(name, ext) = 'abc.txt',尽量拆解为等值条件组合 - ORDER BY 中用它们会导致 filesort,大数据量时延迟明显
跨 MySQL 版本和迁移到其他数据库要注意什么?
CONCAT 是 SQL 标准函数,PostgreSQL/SQL Server 都有同名函数,但行为不完全一致;CONCAT_WS 是 MySQL 特有,PostgreSQL 用 STRING_AGG 或 ARRAY_TO_STRING 替代,SQL Server 得靠 STRING_AGG(2017+)或 XML 技巧。
- MySQL 5.7 和 8.0 对
CONCAT的 NULL 处理完全一致,不用升级适配 - 导出数据给其他系统时,别依赖
CONCAT_WS的 NULL 跳过逻辑,先用COALESCE显式转空串更稳妥 - ORM 框架(如 Django ORM、MyBatis)对这两个函数的支持程度不一,有些只封装了
CONCAT,CONCAT_WS得手写原生 SQL
SELECT COUNT(*) FROM t WHERE col IS NULL 看一眼,比事后调半天快得多。










