You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pandas含中文字符DataFrame写入数据仓库乱码问题求助

解决Pandas+pyodbc写入数据仓库中文乱码问题

老哥,你遇到的中文乱码问题主要出在两个地方:动态拼接SQL时的编码处理漏洞,还有pyodbc的编码配置没到位。另外直接拼SQL不仅容易乱码,还会有SQL注入风险,咱们直接一步到位解决,看下面的方案:

第一步:确认数据仓库表结构

首先得确保你要写入的表,对应的列是支持Unicode的类型:

  • SQL Server:用NVARCHAR/NTEXT(别用VARCHAR/TEXT,单字节存不下中文)
  • MySQL:把列设为utf8mb4编码的VARCHAR/TEXT
  • PostgreSQL:直接用TEXT或VARCHAR(默认支持UTF-8)
    如果表结构不对,再怎么调代码都白搭!

第二步:调整pyodbc的编码配置

你原来的setencoding只设了SQL_CHAR,这是单字节字符类型,中文是多字节的,得换成SQL_WCHAR(对应Unicode),还要加上解码设置:

cnxn = database_connect()
# 同时设置编码和解码,确保双向UTF-8支持
cnxn.setencoding(encoding='utf-8', ctype=pyodbc.SQL_WCHAR)
cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8')
cnxn.autocommit = True
cursor = cnxn.cursor()

第三步:用参数化查询代替动态拼接SQL

这是解决乱码最关键的一步!动态拼字符串时,编码很容易在拼接过程中丢失,而参数化查询会让pyodbc自动处理编码转换,还能防SQL注入。修改后的代码如下:

# 读取CSV的代码保持不变
df = pd.read_csv(filename, dtype='str', encoding='UTF-8')

# 构造参数化INSERT模板:用?作为占位符(pyodbc标准写法)
columns_str = ', '.join(clm)
placeholders = ', '.join(['?'] * len(clm))
insert_sql = f"INSERT INTO {tablename} ({columns_str}) VALUES ({placeholders})"

# 遍历DataFrame每一行写入
for row_idx, row in df.iterrows():
    # 处理NaN为空字符串,同时清理单引号(避免参数里的单引号干扰)
    row_values = []
    for val in row:
        if pd.isna(val):
            row_values.append('')
        else:
            cleaned_val = str(val).strip().replace("'", "")
            row_values.append(cleaned_val)
    
    try:
        # 把参数列表传给execute,pyodbc自动处理编码
        cursor.execute(insert_sql, row_values)
        print(f"第 {row_idx+1} 行写入成功")
    except Exception as e:
        print(f"写入第 {row_idx+1} 行出错:{str(e)}")
        print(f"出错的行数据:{row_values}")

为什么这样能解决问题?

  1. 参数化查询:pyodbc会把参数作为Unicode字符串传递给数据库,完全绕开了手动拼接时的编码丢失问题。
  2. SQL_WCHAR配置:明确告诉pyodbc用Unicode类型处理字符串,完美适配中文等多字节字符。
  3. 安全可靠:避免了SQL注入风险,比动态拼接SQL规范得多。

按这个方案改完,中文应该就能正常显示了!

内容的提问来源于stack exchange,提问作者KARTHI KEYAN

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:23:40