使用pyodbc操作SQL Server时特殊字符显示为问号的问题求助
解决pyodbc插入SQL Server特殊字符变为问号的问题
核心原因
特殊字符(如″)丢失是因为字段类型非Unicode或连接未正确处理Unicode编码,SQL Server中varchar是单字节编码,无法存储超出ASCII的字符,会自动替换为?。
具体解决方案
1. 修改表字段为Unicode类型
确保创建表时,所有存储字符串的字段使用nvarchar(max)(推荐)或nchar类型,而非varchar/char。修改你的create_table函数,字段定义示例:
def create_table(cursor, table_name, fields): # 生成字段定义:每个字段设为nvarchar(max) field_defs = ", ".join([f"[{field}] nvarchar(max)" for field in fields]) query = f"CREATE TABLE {table_name} ({field_defs})" cursor.execute(query)
2. 修正连接字符串,启用Unicode支持
在create_conn函数的连接字符串中添加CHARSET=UTF8,并使用最新的ODBC驱动(如ODBC Driver 17 for SQL Server):
def create_conn(): conn_str = ( "DRIVER={ODBC Driver 17 for SQL Server};" "SERVER=你的服务器地址;" "DATABASE=你的数据库名;" "UID=用户名;" "PWD=密码;" "Encrypt=yes;" "TrustServerCertificate=yes;" "CHARSET=UTF8" ) cnxn = pyodbc.connect(conn_str) cursor = cnxn.cursor() return cursor, cnxn
3. 使用参数化查询,避免字符串拼接
你的现有代码通过拼接SQL生成插入语句,不仅有SQL注入风险,还会导致编码处理异常。改用pyodbc的参数化查询:
def insert_record(table_name, op_rec): cursor, cnxn = create_conn() op_rec = remove_none(op_rec) fields = list(op_rec.keys()) if not check_table_exists(cursor, table_name): create_table(cursor, table_name, fields) # 生成参数化占位符和SQL语句 placeholders = ", ".join(["?"] * len(fields)) query = f"INSERT INTO {table_name} ({', '.join(fields)}) VALUES ({placeholders})" # 直接传入参数,pyodbc会自动处理Unicode编码 cursor.execute(query, list(op_rec.values())) cnxn.commit() # 注意:pyodbc中用连接对象提交,而非游标 cursor.close() cnxn.close()
4. 验证数据库排序规则
确保数据库/表的排序规则支持Unicode(如Chinese_PRC_CI_AS、SQL_Latin1_General_CP1_CI_AS等),默认排序规则通常无需修改,只要字段类型正确即可。
为什么之前的方法无效
你参考的是MySQL相关的解决方案,SQL Server的字符编码处理逻辑与MySQL完全不同,照搬会导致语法错误,且无法解决问题。
内容的提问来源于stack exchange,提问作者silpa
相关产品推荐
相关产品推荐

