在 SQL 里拼接姓名、地址、标签这类多字段字符串时,很多人先想到的都是 CONCAT。但一旦数据库换成 MySQL、PostgreSQL、SQL Server 或 Oracle,NULL 的处理方式、参数数量限制、兼容版本要求都会变,表面上只是函数名相同,实际结果可能完全不同。
这篇文章按数据库分别整理常见写法和行为差异,重点放在最容易踩坑的 NULL 传播、连接操作符替代方案,以及多字段拼接时该怎么写更稳。看完你可以直接判断:当前环境下应该继续用 CONCAT,还是改用 ||、+、IFNULL/COALESCE,甚至 LISTAGG。
MySQL:支持多参数,但最怕 NULL 传染
MySQL 的 CONCAT 可以直接接收多个参数,不需要嵌套调用。字段、字符串字面量、函数返回值都可以按顺序参与拼接。

SELECT CONCAT(first_name, ' ', last_name) FROM users;
它的关键特点是:只要任意一个参数是 NULL,整个结果就会返回 NULL。这也是 MySQL 里最常见的拼接错误来源。
为什么 MySQL 里要先处理可空字段
- 空字符串
''不会影响拼接结果。 - 但
NULL会直接“污染”整个结果。 - 字段可能为空时,通常要先用
IFNULL或COALESCE兜底。
CONCAT(IFNULL(first_name, ''), ' ', IFNULL(last_name, ''))
如果表结构里这些字段允许为空,这一步最好不要省。否则 SQL 能执行,结果却可能整列变成 NULL。
PostgreSQL:可用 CONCAT,也常见 || 写法
PostgreSQL 9.1+ 提供了标准 CONCAT 函数,老版本或很多历史代码里也常见双竖线 || 作为连接符。
CONCAT 和 || 的区别要看清
这两种写法都能完成字符串拼接,但在语义上并不完全一样:
CONCAT(col1, col2)会忽略NULL值。col1 || col2使用的是操作符写法,遇到NULL时表现和CONCAT不同,不能简单当成等价替代。
如果项目里希望写法统一、语义更直观,优先使用 CONCAT 会更稳妥。
SELECT CONCAT(first_name, ' ', middle_name, ' ', last_name) FROM people;
即使 middle_name 是 NULL,结果也会继续返回拼接后的字符串,而不是整行失败。
PostgreSQL 里还有一个容易忽略的返回值细节
PostgreSQL 的 CONCAT 至少要有一个非 NULL 参数;如果所有参数都是 NULL,返回的是空字符串,不是 NULL。这会影响后续判断逻辑,尤其是在你还要继续做比较、过滤或导出时。
SQL Server:2012+ 才有 CONCAT,旧版本还得靠 +
SQL Server 从 2012 开始支持 CONCAT。这个函数的设计目的很明确,就是避免使用 + 拼接时,一遇到 NULL 就把整条结果带成 NULL。
新旧版本写法差别很大
- SQL Server 2012+:可以直接用
CONCAT。 - SQL Server 2008 等旧版本:只能用
ISNULL配合+手工处理。
新版本里,CONCAT 会自动把参数转成字符串,并跳过 NULL。
CONCAT(name, age)
这里如果 age 是 int,也会被隐式转换成字符串,不需要额外 CAST。
为什么不要把 + 和 CONCAT 混着写
- 用
+时,必须手动写ISNULL(col, '')。 - 漏掉任意一项,整行结果都可能变成
NULL。 - 而
CONCAT本身已经处理了这个问题。
所以在 SQL Server 2012+ 环境里,除非要兼容历史代码,否则没有必要继续坚持 + 拼接。
Oracle:原生 CONCAT 只支持两个参数
Oracle 的原生 CONCAT 只能接收两个参数,这一点和前面几个数据库差异很大。只要字段数量超过两个,就必须嵌套调用,或者直接改用 ||。
多字段拼接时,|| 才是主流写法
例如下面这种嵌套调用,虽然能用,但可读性一般,而且括号一多就容易写错:
CONCAT(CONCAT(first, ' '), last)
实际开发中更常见的是:
first || ' ' || middle || ' ' || last
这种写法更直观,也更适合多字段连续拼接。原文场景下,|| 对 NULL 的处理可以理解为“留空”,不会像 MySQL 的 CONCAT 那样直接中断整个结果。
拼接多行值时,不要误用 CONCAT
如果需求不是“把多个字段拼成一个字符串”,而是“把多行记录合并成一行文本”,那就已经不是 CONCAT 的适用场景了。在 Oracle 中应使用:
LISTAGG(email, '; ') WITHIN GROUP (ORDER BY email)
比如一个人有多个邮箱地址,需要按分号合并显示时,LISTAGG 才是对应方案。
最后要记住的判断标准
同样是拼接多个字段,不同数据库真正拉开差距的不是函数名,而是三个细节:是否支持多参数、遇到 NULL 怎么处理、有没有版本限制。

- MySQL:支持多参数,但任意参数为
NULL时整体返回NULL。 - PostgreSQL:
CONCAT会忽略NULL,也常见||写法,但两者语义不能混看。 - SQL Server:
CONCAT需要 2012+,旧版本仍要依赖ISNULL++。 - Oracle:原生
CONCAT只支持两个参数,多字段通常直接用||;多行聚合则用LISTAGG。
真正上线前,最好先确认字段是否允许为空,再结合数据库类型选写法。只记住 CONCAT 这个名字远远不够,NULL 行为和版本边界才是决定结果是否正确的关键。













