读取CSV需先试encoding='gbk'或'utf-8-sig'、sep适配分隔符,首行非列名则header=None;连SQL Server须匹配驱动名、实例名用.或localhostSQLEXPRESS,批量插入启用fast_executemany并分块处理,建表优先于自动推断schema。

用 pandas.read_csv 读取 CSV 时注意编码和分隔符
很多失败直接卡在这一步:中文乱码、列错位、首行被当列名但实际不是。默认 read_csv 用 utf-8,但 Windows 记事本保存的 CSV 常是 gbk 或 gb2312;分隔符也不一定是逗号,可能是制表符或分号。
- 先试
encoding='gbk'或encoding='utf-8-sig'(处理 BOM) - 用
sep=' '或sep=';'替代默认逗号,必要时加on_bad_lines='skip' - 如果首行不是字段名,加
header=None,再手动设columns=... - 数值列含逗号(如“1,234.56”)会导致类型推断错误,建议加
thousands=','
用 pyodbc 连 SQL Server 要配对驱动和连接字符串
连不上基本是驱动没装对或连接字符串写错。Windows 自带 ODBC Driver 17 for SQL Server,Linux/macOS 必须手动装 msodbcsql17;SQL Server Native Client 已弃用,别用。
- 连接字符串里
DRIVER名必须和系统已注册的完全一致,查法:pyodbc.drivers() - 本地实例名不是
localhost,而是localhost\SQLEXPRESS或.(点号代表默认实例) - 密码含特殊字符(如
@、;)要 URL 编码,或改用Trusted_Connection=yes走 Windows 认证 - 别用
autocommit=True,批量插入时关掉它,最后统一commit()更快
用 to_sql 直接入库容易崩,优先选 fast_executemany + 手动 insert
DataFrame.to_sql 默认逐行 INSERT,万级数据就明显变慢;开 method='multi' 也只拼一批语句,不解决根本问题。SQL Server 原生支持批量绑定,关键在 pyodbc 的 fast_executemany 开关。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 创建连接时加
conn = pyodbc.connect(..., autocommit=False),然后conn.fast_executemany = True - 用
cursor.executemany("INSERT INTO t (a,b) VALUES (?,?)", df.values.tolist()) -
df.values.tolist()会丢列名和 dtype,务必提前用df.astype(str).fillna('')清洗空值,否则None传给?会报Invalid parameter type - 单次
executemany别超 1000 行,分块处理更稳:for i in range(0, len(df), 1000): ... df[i:i+1000].values.tolist()
字段类型不匹配导致插入失败,得提前建表或动态映射
SQL Server 对 datetime、bit、decimal 敏感,pandas 的 object 列一塞进去就报错。别指望 to_sql(if_exists='replace') 自动生成合理 schema —— 它把所有 object 当 nvarchar(255),数字当 float,时间当 datetime64 但精度不对。
立即学习“Python免费学习笔记(深入)”;
- 生产环境强烈建议先手工建好目标表,明确指定
varchar(50)、decimal(18,2)、datetime2(3)等 - 若必须自动建,用
dtype参数显式传字典:{'price': sqlalchemy.types.DECIMAL(10,2), 'created': sqlalchemy.types.DateTime()} -
bit字段对应 Python 的bool,不是int或字符串'1';datetime列含 NaT 要先df['ts'].fillna(pd.Timestamp('1900-01-01'))
真正卡住的往往不是代码逻辑,而是 CSV 里藏了不可见字符、SQL Server 的 IDENTITY 列没关自增、或是事务日志满导致 commit 挂起——这些没法靠“自动”绕过,得看日志、查 sys.dm_exec_requests、留心每次 executemany 后的 cursor.rowcount 是否匹配预期行数。

















