使用SQLAlchemy向SQL Server写入数据时编码错误求助
问题
我尝试用SQLAlchemy把数据写入SQL Server,代码如下:
def engine_(): db_user = '' db_password = '' db_host = '' db_name = '' connection_format = 'mssql+pymssql://{0}:{1}@{2}/{3}?charset=utf8' connection_str = connection_format.format(db_user, db_password, db_host, db_name) engine = sqlalchemy.create_engine(connection_str) return engine engine = engine_() df.to_sql('111', con=engine, index=False, if_exists='replace')
执行后报错,改成charset=GBK还是报错。排查后发现是title列的编码问题,试过用str.normalize('NFKD')处理但没用。请问怎么解决?为什么用charset=utf8会触发20002错误?
部分title数据示例:
| title |
|---|
| Artificial Plant Simulation Flower Lotus Water Lily Cumpleaños Para Niña |
| 10cm artificial floating water lily EVA lotus pond ornaments artificial lotus pond aquarium plant ornaments |
| Gauge White Floral Stem Wire Iron Wire Artificial Flower Arrangement Wrapping Strip For Wedding Party DIY Flower Craft |
解决方案
一、charset=utf8触发20002错误的原因
20002是pymssql的连接错误码,核心问题是SQL Server与pymssql的UTF-8支持不兼容:
- SQL Server默认采用UTF-16(对应nvarchar/ntext类型)或GBK(对应varchar/text类型)编码,而pymssql的
charset=utf8参数会强制以UTF-8编码传输数据,两者编码规则不匹配,直接导致连接或数据写入时的编码转换失败。 - 另外pymssql本身对UTF-8的支持存在bug,遇到示例里的
ñ这类特殊字符时,极易出现编码冲突触发报错。
二、具体解决方法
1. 换用pyodbc驱动替代pymssql
这是最稳定的方案,pyodbc对SQL Server的字符集支持更完善,无需手动指定charset:
def engine_(): db_user = '' db_password = '' db_host = '' db_name = '' # 使用pyodbc连接格式,需提前安装ODBC Driver 17 for SQL Server connection_str = f'mssql+pyodbc://{db_user}:{db_password}@{db_host}/{db_name}?driver=ODBC+Driver+17+for+SQL+Server' engine = sqlalchemy.create_engine(connection_str) return engine engine = engine_() df.to_sql('111', con=engine, index=False, if_exists='replace')
注意:先执行pip install pyodbc安装依赖,同时确保系统已安装微软官方的ODBC Driver 17 for SQL Server。
2. 强制数据库列使用Unicode类型(保留pymssql的情况)
如果必须用pymssql,要确保SQL Server表中title列是nvarchar(Unicode类型),而非varchar,可以在to_sql中指定数据类型:
from sqlalchemy import NVARCHAR df.to_sql( '111', con=engine, index=False, if_exists='replace', dtype={'title': NVARCHAR(length=255)} # 强制title列使用NVARCHAR类型 )
同时把连接字符串的charset参数改为utf8mb4或直接删除,让pymssql自动适配SQL Server的Unicode编码。
3. 预处理文本清理无效字符
如果仍有特殊字符报错,可手动过滤无法编码的无效字符:
def clean_title(text): # 过滤掉无法用UTF-8编码的字符 return text.encode('utf-8', errors='ignore').decode('utf-8') df['title'] = df['title'].apply(clean_title)
这个方法能剔除SQL Server无法识别的特殊编码字符,避免写入时触发错误。
内容的提问来源于stack exchange,提问作者1670511081
相关产品推荐
相关产品推荐

