使用Python pandas.read_sql通过ODBC读取数据出现utf-16-le解码错误如何解决?
UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 34-35: illegal UTF-16 surrogate
问题根因
该错误产生的核心原因是你查询的指定字段在数据库中实际存储的编码,与数据库连接驱动默认使用的utf-16-le解码规则不匹配,字段字节流中存在不符合utf-16-le编码规范的序列,导致解码中断。
适配你业务场景的解决方案
你的流程涉及DB1读、DF计算、DB2写三个环节,可按优先级从高到低尝试以下方案:
1. 调整数据库连接参数(优先方案)
从读取源头解决编码不匹配问题,避免后续额外转码处理:
- 先确认DB1、DB2中问题字段的实际存储编码(常见为utf8mb4、GBK、Latin-1等),建立数据库连接时显式指定编码参数,覆盖驱动的默认配置:
- 若用pymysql连接MySQL:连接参数新增
charset='utf8mb4' - 若用pyodbc连接SQL Server:连接参数新增
charset='UTF-8'(替换为实际编码即可) - 所有数据库连接均可新增解码异常处理参数:
encoding_errors='replace',遇到非法字节时自动用占位符替换,避免程序直接中断
- 若用pymysql连接MySQL:连接参数新增
- 不确定字段实际编码时,先以二进制形式读取字段内容手动探测:
# 查询时将问题字段转为二进制格式返回 query = "SELECT CAST(问题字段名 AS BINARY) as problem_col FROM 表名" df1 = pd.read_sql(query, db1_conn) # 用chardet探测编码规则 import chardet print(chardet.detect(df1['problem_col'].iloc[0]))
拿到探测结果后,再把连接的charset参数改成对应的编码即可。
2. 读取后手动处理解码异常
如果连接层调整后仍有报错,直接对读取到的字段做自定义解码:
# 替换errors参数可调整异常处理逻辑 # ignore:直接丢弃非法字节;replace:用�替换非法字符;surrogateescape:保留非法字节后续可无损转回 df1['问题字段名'] = df1['问题字段名'].apply( lambda x: x.decode('utf-16-le', errors='replace') if isinstance(x, bytes) else x )
3. 写入DB2前的编码适配
计算完成写入DB2前,统一转码为DB2对应字段要求的编码,避免写入时报错:
# 假设DB2目标字段要求utf-16-le编码,统一转码后再写入 df_result['目标字段名'] = df_result['目标字段名'].apply( lambda x: x.encode('utf-16-le', errors='replace').decode('utf-16-le') if isinstance(x, str) else x )
内容的提问来源于stack exchange,提问作者Wes
相关产品推荐
相关产品推荐

