标准SQL中无统一CONCAT行为:MySQL支持但遇NULL返回NULL,PostgreSQL用||、SQL Server用+,均因NULL导致结果为NULL;跨库应使用COALESCE()预处理空值后再拼接。

标准 SQL 里没有 CONCAT() 的统一行为——它在 MySQL 里可用,在 PostgreSQL 里要加 ||,而 SQL Server 用 +,但空值会直接让整行变 NULL。所以真要跨数据库兼容,得靠 COALESCE() + ||(或等价拼接操作)组合来兜底。
用 || 拼接并处理 NULL
ANSI SQL 标准规定字符串拼接用双竖线 ||,但它的致命问题是:任一操作数为 NULL,结果就是 NULL。比如 first_name || ' ' || last_name,只要 first_name 是 NULL,整个全名就消失。
- 必须对每个字段做非空兜底:
COALESCE(first_name, '') || ' ' || COALESCE(last_name, '') - 中间空格也建议用
COALESCE包一层,避免多空格(如中间名为空时):COALESCE(first_name, '') || COALESCE(' ' || middle_name || ' ', ' ') || COALESCE(last_name, '') - PostgreSQL 和 Oracle 原生支持
||;SQLite 默认开启SQLITE_ENABLE_NULL_HANDLING才认它,否则要用CONCAT()
MySQL 的 CONCAT() 自动跳过 NULL,但有坑
MySQL 的 CONCAT() 确实把 NULL 当空字符串处理,看起来省事,但它不遵循 ANSI 标准,迁移到其他库会出错。
-
CONCAT(first_name, ' ', middle_name, ' ', last_name)在 MySQL 里能跑,但在 PostgreSQL 里报错:function concat(unknown, unknown, unknown, unknown, unknown) does not exist - 如果字段是
TEXT类型且含换行符,CONCAT()会原样拼进去,显示成乱码——得提前用REPLACE(col, '\n', ' ')清洗 - MySQL 8.0+ 支持
CONCAT_WS(' ', first_name, middle_name, last_name),自动跳过NULL并用空格分隔,比手写CONCAT()更安全
SQL Server 要防 + 运算符的隐式转换和 NULL 中断
SQL Server 用 + 拼字符串,但它是“严格模式”:任意一边是 NULL,结果必为 NULL;而且如果字段是数字类型(比如 id 字段误参与拼接),会触发隐式转换失败。
- 必须全部显式转字符串:
ISNULL(CAST(first_name AS VARCHAR(50)), '') + ' ' + ISNULL(CAST(last_name AS VARCHAR(50)), '') -
ISNULL()比COALESCE()性能略好(前者单类型,后者需类型推导),但只支持两个参数,多字段得嵌套 - 若列定义为
VARCHAR(MAX),拼接后结果类型仍是VARCHAR(MAX),可能拖慢排序或索引查找——必要时用CAST(... AS VARCHAR(100))截断
真正麻烦的不是语法本身,而是不同数据库对空值、类型、截断长度的默认策略不一致;哪怕写对了拼接逻辑,上线后发现 PostgreSQL 返回空,SQL Server 报类型错误,八成是某个字段悄悄存了 NULL 或不可见字符——查之前先 SELECT LENGTH(TRIM(col)) 看看真实长度。

















