使用pgLoader从SQL Server迁移数据至PostgreSQL时遭遇特殊字符(ñ/í等)编码错误
看起来你遇到的是典型的编码链条不匹配问题——虽然脚本里指定了编码,但Windows Server环境下的系统编码、SQL Server实际数据编码和pgLoader的解析编码没对齐,导致出现了UTF8字节解析错误。我之前帮朋友解决过类似的Windows Server下pgLoader迁移问题,给你一步步排查和解决的方案:
先拆解错误根源
报错里的BABEL-ENCODINGS:INVALID-UTF8-STARTER-BYTE是关键信号:pgLoader在把SQL Server的编码数据转成PostgreSQL可识别的格式时,遇到了无法解析的字节。虽然你脚本里设了client_encoding = 'WIN1252',但Windows Server的系统默认编码、SQL Server的实际列 collation 可能和你之前的Docker Windows环境不一样。
具体解决步骤
1. 先确认SQL Server的实际数据编码
先查目标表中含特殊字符列的collation(对应实际编码),在SQL Server中执行:
SELECT col.name AS column_name, col.collation_name FROM sys.columns col JOIN sys.tables tbl ON col.object_id = tbl.object_id WHERE tbl.name = 'DRecords' AND col.collation_name IS NOT NULL;
- 如果结果是
SQL_Latin1_General_CP1_CI_AS/Modern_Spanish_CI_AS,确实对应WIN1252; - 如果是其他collation(比如
Chinese_PRC_CI_AS对应GBK),你脚本里的WIN1252就需要改成对应的PostgreSQL编码名(比如GBK)。
2. 调整pgLoader脚本的编码指定逻辑
在连接SQL Server时明确指定读取编码,避免pgLoader自动检测错误,同时在PostgreSQL会话中重复设置编码确保一致:
- 把
FROM连接串改成:FROM mssql://sa:sa@172.22.0.1/ADB?encoding=WIN1252 - 把
client_encoding的设置移到BEFORE LOAD的SQL块里,确保会话生效:BEFORE LOAD DO $$ SET session_replication_role = replica; SET client_encoding = 'WIN1252'; $$
3. 先小批量测试+记录错误
先把批量行数改小,加上错误日志,定位具体是哪一行的字符出问题:
在WITH参数里添加:
batch rows = 1000, log errors to 'drecords_load_errors.log'
这样可以看到具体的错误行内容,方便你验证编码是否真的匹配。
4. 适配Windows Server的系统编码
Windows Server的默认控制台编码可能和Windows 10不同,在运行pgLoader之前,先在命令行里执行以下命令,强制设置当前会话的编码:
chcp 1252 set LANG=en_US.WIN1252
再运行pgLoader脚本,避免系统编码干扰pgLoader的解析。
修改后的完整测试脚本
-- 调整后的测试用脚本 LOAD DATABASE FROM mssql://sa:sa@172.22.0.1/ADB?encoding=WIN1252 INTO postgresql://postgres:sa@172.22.0.1/ADB WITH data only, -- 仅复制数据,不修改表结构 disable triggers, no foreign keys, quote identifiers, batch rows = 1000, -- 小批量测试定位问题 prefetch rows = 1000, log errors to 'drecords_load_errors.log' -- 记录错误行详情 CAST type varchar TO text, type nvarchar TO text, type text TO text SET work_mem to '256MB', maintenance_work_mem to '1GB' ALTER SCHEMA 'dbo' RENAME TO 'public' INCLUDING ONLY TABLE NAMES LIKE 'DRecords' IN SCHEMA 'dbo' BEFORE LOAD DO $$ SET session_replication_role = replica; SET client_encoding = 'WIN1252'; $$ AFTER LOAD DO $$ SET session_replication_role = DEFAULT; $$;
最后总结
核心是确保SQL Server数据编码 → pgLoader读取编码 → PostgreSQL会话编码这一整条链条完全对齐。先通过小批量测试定位具体错误行,确认编码匹配后再放大批量参数。如果测试后还是有问题,把错误日志里的具体行贴出来,就能精准定位是某个特殊字符的编码问题了。




