concat遇null即返回null,污染整个表达式;concat_ws跳过null但要求分隔符非null,且非分隔符参数必须为字符串类型,空字符串''被保留而null被忽略。

CONCAT遇到NULL直接返回NULL
只要任意一个参数是NULL,整个CONCAT()结果就是NULL,哪怕其他全是有效字符串。这不是“空字符串”,而是真正的SQL NULL——它会污染整个表达式,比如在WHERE、ORDER BY或聚合计算中引发意外逻辑中断。
常见错误现象:
-
SELECT CONCAT(first_name, ' ', last_name) FROM users→ 某行last_name为NULL,该行结果全为NULL,前端显示为空或丢失整条记录 - 用
CONCAT拼接用于IN子句的字符串列表时,因单个NULL导致整个条件失效
不能靠IFNULL()或COALESCE()临时包裹每个字段来救火——写法冗长且易漏,尤其字段多时。
CONCAT_WS忽略NULL但要求分隔符非NULL
CONCAT_WS()的设计逻辑是:跳过所有值为NULL的参数,只拼接非NULL字符串,并用第一个参数(分隔符)隔开它们。但注意:分隔符本身不能为NULL,否则整个函数返回NULL。
典型使用场景:
- 拼接地址字段:
CONCAT_WS(', ', street, city, province, country)→ 自动跳过为空的province,输出类似"中山路, 杭州, 中国" - 生成带分隔符的标签列表:
CONCAT_WS('|', tag1, tag2, tag3)→ 即使tag2是NULL,仍得"web|db"
容易踩的坑:
- 误把字段当分隔符:
CONCAT_WS(name, ', ', email)→ 如果name为NULL,整条结果变NULL,不是你想要的“跳过” - 分隔符用变量未校验:
CONCAT_WS(@sep, a, b),若@sep是NULL,结果崩掉
INT类型参数能否直传?
CONCAT()对类型宽松:传入整数、日期、布尔值都自动转字符串,CONCAT(1, '-', 2) → "1-2"。
CONCAT_WS()严格得多:除分隔符外,所有待拼接参数**必须是字符串类型**。传INT会报错:
SELECT CONCAT_WS(',', 1, 'a', 2);
MySQL报错:Incorrect argument type to function concat_ws 或明确提示 Argument 2 (1) must be of type string(Hive/Spark SQL中更常见此提示)。
所以实际写法必须显式转换:
- MySQL用
CAST(col AS CHAR)或CONVERT(col, CHAR) - 避免
CONCAT_WS(',', id, name),改写为CONCAT_WS(',', CAST(id AS CHAR), name)
空字符串''和NULL在两者中行为不同
CONCAT()把空字符串''当普通字符处理,不影响结果;但NULL一票否决。
CONCAT_WS()对''和NULL区别对待:
-
NULL被跳过(不参与拼接) -
''被保留,会出现在结果里:CONCAT_WS(',', 'a', '', 'c')→"a,,c"
这意味着:如果你依赖CONCAT_WS做“安全拼接”,却忘了清洗数据里的空字符串,可能得到带多余分隔符的脏结果,比如"name,,city"。
真正要兼顾NULL和''的场景,得组合用:CONCAT_WS(',', NULLIF(col1,''), NULLIF(col2,''))。











