REPLACE函数用于纯字符串逐字匹配与全量替换,语法为REPLACE(string, old_substring, new_substring),三参数缺一不可且顺序不可颠倒;不支持正则、不识别词边界、NULL输入返回NULL、空字符串作old_substring通常无效。

REPLACE函数的基本用法和参数顺序
SQL的REPLACE函数不是正则替换,而是纯字符串逐字匹配+全量替换,语法是REPLACE(string, old_substring, new_substring)。三个参数缺一不可,顺序不能颠倒——写成REPLACE(col, 'a', '')可以删掉所有a,但写成REPLACE(col, '', 'x')会报错或返回空(取决于数据库),因为空字符串作为old_substring在多数引擎中不被允许。
常见错误现象:REPLACE(name, 'Mr.', 'Mr')本意是去掉点,结果把Mr. Smith变成Mr Smith,但若字段里有MrX也会被误替换成MrX→MrX(没变),而Mr.结尾的才生效——它不认词边界,只认连续字面量。
- MySQL、PostgreSQL、SQL Server、SQLite 都支持标准三参数
REPLACE,行为一致 - Oracle 用
REPLACE,但不支持NULL作为old_substring,否则整个表达式返回NULL - 想只替换首次出现?标准
REPLACE做不到,得靠SUBSTRING+CHARINDEX(SQL Server)或STRPOS+LEFT/RIGHT(PostgreSQL)拼接
WHERE条件必须加,否则整表字段全被改
执行UPDATE t SET col = REPLACE(col, 'foo', 'bar')前,如果漏了WHERE,所有行都会被扫一遍,哪怕内容根本不含foo——这时REPLACE返回原值,看似“没变”,但实际触发了全表更新,可能锁表、写binlog、触发触发器,风险极大。
正确姿势是先查再更:
SELECT id, col FROM t WHERE col LIKE '%foo%';确认范围后,再执行带条件的
UPDATE。
-
WHERE col LIKE '%旧内容%'比WHERE col IS NOT NULL更精准,避免无效更新 - 如果旧内容含通配符(如
%、_),得用ESCAPE,例如WHERE col LIKE '%100\% off%' ESCAPE '\' - 某些ORM自动生成的SQL可能隐式加
WHERE 1=1,要人工核对最终下发语句
嵌套REPLACE实现多段独立替换
一个REPLACE只能处理一种子串,但可以嵌套调用实现多个替换,比如把<、>、&都转义:
REPLACE(REPLACE(REPLACE(col, '<', '<'), '>', '>'), '&', '&')。注意嵌套顺序:最外层的
REPLACE最后执行,所以要把&留到最后替,否则里的<code>&会被提前干掉。
性能影响明显:每层REPLACE都要扫描整字段,三层就是三次全字段遍历。大文本字段(如TEXT)上慎用,可考虑应用层分步处理。
- PostgreSQL 用户可用
TRANSLATE一次性换多个单字符:TRANSLATE(col, '&', '@@#') - MySQL 8.0+ 支持
REGEXP_REPLACE,适合模式化替换,但正则开销更大,且语法和PCRE不完全兼容 - 别用
REPLACE(REPLACE(...))去模拟大小写转换,UPPER/LOWER才是正解
NULL值和空字符串的陷阱
REPLACE遇到NULL输入直接返回NULL,不会报错也不会跳过。比如REPLACE(nullable_col, 'x', 'y'),只要nullable_col是NULL,结果就是NULL,不是原值。
空字符串''作new_substring可以删内容(如REPLACE(col, ' ', '')去空格),但作old_substring在多数数据库中无效:REPLACE(col, '', 'x')通常返回NULL或原值,行为不一致,务必避免。
- 安全写法是显式处理
NULL:COALESCE(REPLACE(col, 'x', 'y'), col),但注意这会让原本NULL的字段变成非NULL - 想保留
NULL又做替换,用CASE WHEN col IS NULL THEN NULL ELSE REPLACE(col, 'x', 'y') END - 测试时用
SELECT col, REPLACE(col, 'x', 'y') FROM t LIMIT 5,亲眼确认NULL和空字符串的输出
REPLACE结果类型处理不一致——MySQL 可能截断,PostgreSQL 保持原类型长度,SQL Server 在varchar(max)上没问题但在varchar(50)上可能隐式转成varchar(50)导致截断。动手前先看目标字段定义。

















