MySQL中||默认是逻辑或而非字符串拼接,需启用PIPES_AS_CONCAT模式;CONCAT遇NULL返回NULL,CONCAT_WS跳过NULL;跨库兼容推荐CONCAT但需处理NULL差异。
MySQL 里用 || 拼字符串,为什么结果是 0 或 NULL?
因为默认情况下,mysql 的 || 不是字符串拼接,而是逻辑或运算符。只有当 sql 模式启用了 pipes_as_concat,|| 才等价于 concat()。
常见错误现象:SELECT 'a' || 'b'; 返回 0(两个非空字符串转布尔都是 TRUE,TRUE OR TRUE = 1?不对——实际是先转数字失败→0),或者在严格模式下直接报错。
- 检查当前模式:
SELECT @@sql_mode;,看是否含PIPES_AS_CONCAT - 临时启用(当前会话):
SET sql_mode = CONCAT(@@sql_mode, ',PIPES_AS_CONCAT'); - 不推荐全局改,尤其在多应用共用实例时,可能破坏依赖标准行为的旧逻辑
CONCAT() 和 CONCAT_WS() 的 NULL 处理差异
CONCAT() 遇到任意参数为 NULL,整条结果就变成 NULL;而 CONCAT_WS()(WS = With Separator)只跳过 NULL 参数,不影响其余部分。
使用场景:拼接用户姓名字段,middle_name 可能为空,用 CONCAT(first, ' ', middle, ' ', last) 一空全空;换成 CONCAT_WS(' ', first, middle, last) 就自然省略空段。
-
CONCAT('a', NULL, 'c')→NULL -
CONCAT_WS('-', 'a', NULL, 'c')→'a-c' -
CONCAT_WS()的第一个参数是分隔符,不能为NULL,否则整个结果为NULL
性能上 || 真的比 CONCAT() 快吗?
在启用了 PIPES_AS_CONCAT 的前提下,两者执行计划、底层处理路径几乎一致,性能差异可忽略——不是语法糖快,是“根本没额外开销”。真正影响性能的是拼接内容本身:字段长度、字符集转换、是否触发隐式类型转换。
容易踩的坑:CONCAT(id, name) 中 id 是 INT,MySQL 会把整行记录的 name 字段也转成 same charset + collation 再拼,若 name 是 utf8mb4 而连接默认字符集是 latin1,就会悄悄触发转换,拖慢查询。
- 显式转码更可控:
CONCAT(CAST(id AS CHAR), name) - 避免混合数值与字符串直接拼接,尤其在 WHERE 或 ORDER BY 中参与计算时
- 高并发拼接长文本(如日志聚合)时,优先考虑应用层做,别压给 MySQL 字符串函数
PostgreSQL / Oracle / SQL Server 怎么看?
别套用 MySQL 经验:|| 在 PostgreSQL 和 Oracle 中原生就是字符串拼接,无需设模式;SQL Server 则完全不支持 ||,必须用 +(且对 NULL 更敏感)或 CONCAT()(SQL Server 2012+)。
跨数据库写法最稳的是 CONCAT(),但要注意:MySQL CONCAT() 不接受 NULL,而 SQL Server 和 PostgreSQL 的 CONCAT() 会自动跳过 NULL —— 同一个函数,在不同库行为不一致。
- MySQL:
CONCAT(NULL, 'a')→NULL - SQL Server:
CONCAT(NULL, 'a')→'a' - 真要移植,要么统一用
COALESCE(col, '')做兜底,要么干脆别拼,让应用层处理


















