Navicat“全局查找替换”仅修改本地文本,不改变数据库;真替换需用REPLACE()+UPDATE语句,注意列类型、WHERE条件及分批执行。
Navicat 的“全局查找替换”不是 PostgreSQL 功能
navicat 里那个带“全部替换”按钮的搜索框,只作用于当前打开的 sql 编辑器窗口或结果集表格,它不发任何 update 或 replace() 到数据库。你点“全部替换”,改的只是本地文本——关掉窗口就丢,表数据纹丝不动。
真正改数据库内容,必须靠 SQL 语句。Navicat 只是帮你写、发、看结果的工具,别把它当数据库本身。
用 REPLACE() + UPDATE 才算真替换
PostgreSQL 没有内置“全库字符串替换”命令,得手动拼 UPDATE。核心是 REPLACE(column_name, 'old', 'new') 函数,但它只处理单列,且大小写敏感。
-
REPLACE()不支持正则,想做模式匹配得换REGEXP_REPLACE() - 必须显式指定表名和列名,不能“整个 schema 一键扫”
- 没加
WHERE条件?整列都会执行替换,哪怕值本来就不含目标字符串 - 字符类型列(
TEXT、VARCHAR)可用;数字、JSON、日期列会报错,得先转成TEXT
示例:把 users 表中 email 列里的 @old.com 换成 @new.org
UPDATE users SET email = REPLACE(email, '@old.com', '@new.org') WHERE email LIKE '%@old.com%';
想跨多张表?别手敲,用 pg_tables 动态生成 SQL
手动写几十个 UPDATE 容易漏表、错列、忘条件。更稳的方式是查系统表,拼出所有要执行的语句,再人工核对后批量运行。
比如找当前 schema 下所有含 description 列的表,并生成替换语句:
SELECT format( 'UPDATE %I SET %I = REPLACE(%I, ''foo'', ''bar'') WHERE %I LIKE ''%%foo%%'';', tablename, column_name, column_name, column_name ) FROM pg_tables t JOIN pg_attribute a ON a.attrelid = t.relid WHERE t.schemaname = 'public' AND a.attname = 'description' AND a.attnum > 0 AND NOT a.attisdropped;
执行结果是一堆 UPDATE 语句,复制进编辑器,逐条检查再运行。
- 注意
format()里的%I会自动加双引号防关键字冲突,比拼字符串安全 -
pg_attribute.attnum > 0排除系统列,NOT attisdropped排除已删列 - 别直接
EXECUTE动态 SQL —— 没法预览、没法回滚、出错难定位
大表替换卡死?加索引、分批次、开事务
在百万行表上跑 UPDATE,不加控制容易锁表、OOM、拖垮线上服务。
- 先确认目标列是否有索引:没有的话,
WHERE条件(如LIKE '%xxx%')基本走不了索引,全表扫描不可避免 - 用
LIMIT分批更新,配合WHERE id BETWEEN x AND y更可控 - 每批用独立事务包裹,避免长事务阻塞其他操作
- 别在业务高峰期跑;替换成前先
pg_dump关键表
示例:按主键分批更新(假设主键叫 id)
UPDATE products SET name = REPLACE(name, 'ABC', 'XYZ') WHERE id >= 10000 AND id < 20000 AND name LIKE '%ABC%';
最常被忽略的是:替换前后字符长度变化可能触发 VARCHAR(n) 长度超限报错,或者让索引失效。动手前,先用 SELECT MAX(LENGTH(REPLACE(...))) 算算新值会不会爆。


















