UPDATE整列需用SUBSTRING/LEFT/RIGHT动态拼接,如邮箱改前缀:SET email=CONCAT('user_', SUBSTRING(email, LOCATE('@',email), LENGTH(email))),务必WHERE过滤NULL和无@记录,并先SELECT验证。

用 SUBSTRING 或 LEFT/RIGHT 拼接实现局部保留
直接 UPDATE 整列时想“留头去尾”或“留尾去头”,不能靠 SET col = 'xxx' 硬覆盖,得用字符串函数动态提取+拼接。核心思路是:先用 SUBSTRING、LEFT 或 RIGHT 截出要保留的部分,再和新内容组合。
比如把邮箱前缀统一改成 user_,但保留域名部分:
UPDATE users SET email = CONCAT('user_', SUBSTRING(email, LOCATE('@', email), LENGTH(email)));注意 LOCATE('@', email) 返回 @ 的位置,从该位置开始截取就保住了 @domain.com。不同数据库函数名略有差异:PostgreSQL 用 SUBSTR(email, STRPOS(email, '@')),SQL Server 用 SUBSTRING(email, CHARINDEX('@', email), LEN(email))。
处理 NULL 或不匹配模式的字段必须加 WHERE 过滤
如果某行 email 是 NULL,或不含 @,LOCATE 返回 0,SUBSTRING(col, 0, ...) 在 MySQL 中会返回 NULL,整条记录可能被意外清空。
- 务必用
WHERE email IS NOT NULL AND email LIKE '%@%'排除脏数据 -
PostgreSQL中STRPOS找不到时返回 0,传给SUBSTR会导致越界,需配合CASE WHEN判断 - 测试时先用
SELECT验证逻辑:SELECT email, CONCAT('user_', SUBSTRING(email, LOCATE('@', email), LENGTH(email))) FROM users WHERE email LIKE '%@%';
MySQL 8.0+ 可用 REGEXP_REPLACE 简化复杂替换
当保留逻辑涉及多段(如“保留前3位+后4位,中间替换成***”),手写 SUBSTRING 嵌套易错。MySQL 8.0+ 支持 REGEXP_REPLACE,更直观:
UPDATE users SET phone = REGEXP_REPLACE(phone, '^(.{3}).*(.{4})$', '$1***$2');这个正则捕获开头3位和结尾4位,中间任意字符被 *** 替代。但要注意:
-
REGEXP_REPLACE在MySQL < 8.0、SQL Server、SQLite中不可用,得回退到SUBSTRING方案 - 正则中
$1、$2是反向引用,不是所有数据库都支持(PostgreSQL用\1、\2) - 确保原始值长度足够,否则
^(.{3})匹配失败,整字段变NULL或原值(取决于数据库行为)
UPDATE 前没备份或没 WHERE 条件是最高危操作
这类更新极易误伤全表。哪怕逻辑看似安全,也必须:
- 在事务里执行:
BEGIN; UPDATE ...; SELECT ROW_COUNT(); -- 确认影响行数后再 COMMIT; - 对大表先加
LIMIT 100(MySQL 支持),验证效果 - 生产环境严禁直接跑
UPDATE table SET col = ...不带WHERE—— 即使你“确定”全表都要改,也显式写成WHERE 1=1并双检 - 字符集敏感操作(如中文截取)注意
LENGTH和CHAR_LENGTH区别:前者按字节,后者按字符,UTF8 下中文占3字节,用错会切歪
真正麻烦的不是函数怎么写,而是截取位置算错一两位,或者忘了某几行数据格式异常,结果批量改坏。动手前花两分钟看三条真实数据的结构,比查十遍文档管用。

















