pandas.read_sql连接对象必须是sqlalchemy engine;直接传sqlite3或pymysql的connection会报错,因pandas要求底层支持execute方法。

用 pandas.read_sql 读取数据库时,连接对象必须是 SQLAlchemy Engine
直接传 sqlite3.connect(...) 或 pymysql 的 Connection 会报错:AttributeError: 'Connection' object has no attribute 'execute'。pandas 要求底层是 sqlalchemy.engine.Engine。
正确做法是用 sqlalchemy.create_engine 构建连接:
from sqlalchemy import create_engine
import pandas as pd
<p>engine = create_engine("sqlite:///example.db")</p><h1>或 MySQL:engine = create_engine("mysql+pymysql://user:pass@localhost/dbname")</h1><p>df = pd.read_sql("SELECT * FROM users", engine)</p>
- SQLite 路径支持相对路径,但注意当前工作目录可能不是脚本所在目录
- MySQL/PostgreSQL 需要安装对应驱动(
pymysql、psycopg2),否则create_engine会抛ModuleNotFoundError - 如果 SQL 语句含参数,别用 Python 字符串格式化,改用
pd.read_sql("SELECT * FROM t WHERE id = :id", engine, params={"id": 123})
to_csv 默认不写表头和索引,但生产环境通常需要显式控制
直接调 df.to_csv("out.csv") 会把 DataFrame 的行索引(index)也写进去,且列名作为第一行——这常被误认为“多了一列”或“首行错位”。
常见组合:
df.to_csv("out.csv", index=False, header=True) # 推荐:无索引,有列名
df.to_csv("out.csv", index=False, header=False) # 纯数据,无列名(适合后续程序解析)
df.to_csv("out.csv", index=True, header=True) # 保留索引(如需溯源 row_id)
-
index=False是最常用选项,尤其导出给 Excel 或其他系统消费时 - 中文列名或数据导出乱码?加
encoding="utf-8-sig"(Windows Excel 友好),不要用utf-8 - 数值列含 NaN,默认转为空字符串;若需统一为
NULL或0,先用df.fillna(...)
大数据量导出 CSV 容易内存爆掉,得流式处理
当表有百万行以上,pd.read_sql 一次性加载全量到内存,再 to_csv,很可能触发 MemoryError 或拖慢整个流程。
替代方案:用 chunksize 分批读 + 追加写入:
with open("large_out.csv", "w", encoding="utf-8-sig") as f:
first_chunk = True
for chunk in pd.read_sql("SELECT * FROM logs", engine, chunksize=50000):
chunk.to_csv(f, header=first_chunk, index=False, mode="a")
first_chunk = False
-
chunksize值不是越大越好,5k–50k 之间较稳妥,取决于单行平均大小和可用内存 - 首次写入需
header=True,后续必须header=False,否则 CSV 每块都带列名 - 不能用
df.to_csv(..., mode="a")直接追加,因为to_csv会重写整个文件头逻辑
导出后 CSV 列顺序/类型和数据库不一致?问题出在 SQL 查询本身
pandas 不会自动按数据库字段定义顺序或类型映射 CSV。比如某列在 DB 是 DATE,读出来是 datetime64[ns],但 to_csv 默认转成字符串(ISO 格式),且毫秒部分可能被截断。
- 确保 SELECT 明确写出字段名,避免
*导致顺序不可控 - 时间列要保留精度?用
parse_dates参数或导出前chunk["created_at"].dt.strftime("%Y-%m-%d %H:%M:%S.%f") - 整数列含 NULL,pandas 会转成
float64(因 NaN 是浮点),导出后带.0。解决:先astype("Int64")(注意是大写 I)再导出
真正卡住的往往不是语法,而是对 SQL 结果结构、pandas 类型推断、CSV 文本本质这三层之间隐式转换的误判。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











