在关系型数据库查询里,经常需要把散落在不同列里的信息拼到一起再返回,比如把省份、城市、区县三个字段连成详细地址,或者将产品编号与批次号合并成可追溯的串码。这种把多个字段显示为一个字符串的操作,本质上就是字符串连接。不同数据库引擎对连接语法的支持程度不一样,有的只认标准函数,有的偏爱运算符,稍不注意就会写出在本机能跑、换库就报错的语句。

CONCAT函数的基本用法与NULL处理规则
CONCAT是SQL标准里定义的字符串连接函数,接受两个或更多参数,按顺序把它们拼成一条结果。在MySQL和SQL Server中,CONCAT可以传入任意多个参数,而在Oracle里老版本只支持两个参数,要连多个就得嵌套调用。使用函数的最大好处是它对NULL更宽容:大多数实现会把NULL当作空字符串处理,而不是让整行结果变成NULL。
比如用户表users里有first_name和last_name,其中某些记录的last_name为NULL。用CONCAT(first_name, last_name)得到的只是名而没有NULL中断。相比之下,如果用加号连接,SQL Server里NULL加任何字符串都等于NULL,整列就空了。下面是一段MySQL的示例,把姓名和邮箱拼起来,中间用竖线隔开:
SELECT CONCAT(first_name, '|', last_name, '|', email) AS user_info FROM users;
需要注意的是,CONCAT不会自动做类型转换的统一处理。如果参数是数字,MySQL会隐式转成字符串,但PostgreSQL的CONCAT也支持,而有些严格模式数据库要求显式用CAST。因此在拼金额、日期这类非字符串字段时,最好自己包一层转换,避免依赖数据库默认行为导致隐式规则变更后查询出错。
使用连接运算符的实现方式与数据库差异
除了函数,很多数据库提供专用连接符。Oracle和PostgreSQL使用双竖线(||)作为连接运算符,SQL Server使用加号(+),MySQL在默认模式下也支持加号但会把字符串转数字再相加,容易出 bug,所以MySQL更推荐CONCAT。下面用Oracle展示用||合并地址字段:
SELECT province || city || district AS full_address FROM locations;
运算符方式写起来直观,但NULL处理很棘手。在Oracle中,NULL || 'x' 结果是'x',看似和CONCAT一样;但在SQL Server里,'x' + NULL 结果是NULL。这种差异使得同一段用加号的脚本在换库时逻辑翻转。另外用加号时如果两边都是数字类型,数据库会做算术加而不是连接,必须保证至少有一边是字符串类型或用CAST强转。
为了兼容多库,有些团队会封装视图或写ORM层统一用CONCAT。如果一定要用运算符,建议在SQL Server里改用CONCAT,在Oracle里用||,并通过测试覆盖NULL场景。下面的SQL Server示例显示加号遇NULL失效,以及改用CONCAT后的正确写法:
-- 错误示范:nickname为NULL时整个结果为NULL
SELECT '用户:' + nickname FROM accounts;
-- 正确写法
SELECT CONCAT('用户:', nickname) FROM accounts;
带分隔符与类型转换的实用合并技巧
实际业务里合并字段通常要加分隔符,比如用逗号连地址,用短横连日期和单号。直接写CONCAT(a, ',', b, ',', c)在字段多时很冗长。MySQL提供了CONCAT_WS函数,第一个参数是分隔符,后面字段自动用该符号连接,并且会跳过NULL而不留下多余分隔符,非常适合做清单串。
SELECT CONCAT_WS(',', province, city, district) AS addr
FROM locations;
当被合并的字段包含日期、数字时,必须转成字符串才能连接,否则数据库可能报错或产生无意义数字相加。以SQL Server为例,把订单日期和金额合并展示,可以用CONVERT处理日期,用CAST处理小数:
SELECT
CONCAT(
CONVERT(varchar(10), order_date, 120),
'_',
CAST(amount AS varchar(20))
) AS order_label
FROM orders;
在PostgreSQL里则用TO_CHAR来格式化日期再拼。掌握这些转换函数配合CONCAT或连接符,就能稳定地把任意类型字段合并显示。建议把常用拼装逻辑写成数据库函数或视图,减少业务代码里的字符串处理负担,也降低因数据库切换带来的语法不兼容风险。