pandas.read_sql需传sqlalchemy.Engine或DB-API连接,非字符串URL;to_excel导出中文需openpyxl引擎并设index=False;大数据用chunksize分批读写;日期/数字格式异常须用openpyxl手动设置number_format。

用 pandas.read_sql 读取数据时,别漏掉数据库连接参数
直接用 pandas.read_sql 最省事,但常见错误是传错连接对象类型:它要的是 sqlalchemy.Engine 或 DB-API 2.0 的 Connection,不是字符串 URL。比如用 sqlite3.connect() 返回的原生连接,得包一层 sqlalchemy.create_engine("sqlite:///db.sqlite") 才能直接用;否则会报 AttributeError: 'Connection' object has no attribute 'execute'。
实际写法示例:
import pandas as pd
from sqlalchemy import create_engine
<p>engine = create_engine("mysql+pymysql://user:pass@localhost/dbname")
df = pd.read_sql("SELECT * FROM users WHERE status = %s", engine, params=[1])- MySQL 用
mysql+pymysql或mysql+mysqldb,PostgreSQL 用postgresql+psycopg2 -
params参数必须是 list/tuple,即使只有一个值也要写成[value] - SQLite 路径写成
sqlite:///./data.db(三个斜杠),少一个就打不开文件
导出 Excel 时,to_excel 默认不带样式,但表头和索引容易出错
to_excel 默认把 DataFrame 索引也写进第一列,多数人不需要。加 index=False 就能去掉;另外如果字段名含中文或特殊字符,Excel 打开可能乱码——这不是编码问题,而是 Excel 本身不支持 UTF-8 BOM,得靠 openpyxl 引擎自动处理(不用手动设编码)。
关键配置项:
立即学习“Python免费学习笔记(深入)”;
df.to_excel("output.xlsx", index=False, engine="openpyxl")- 必须提前
pip install openpyxl,否则报ValueError: No engine for filetype 'xlsx' - 不要用
xlsxwriter引擎导出含中文的表头,它默认不支持 Unicode 字体渲染 - 如果导出多张 Sheet,用
ExcelWriter上下文管理器,避免文件句柄没释放导致“Permission denied”
大数据量导出卡死?用分块读取 + 追加写入
查几百万行数据时,read_sql 一次性加载会爆内存,Excel 文件本身也有行数限制(1048576 行)。解决方案不是“换工具”,而是控制读写节奏:
- 用
chunksize参数分批读:pd.read_sql(sql, engine, chunksize=10000) - 第一次写用
ExcelWriter,后续每块调sheet_name和startrow追加,别反复打开关闭文件 - 写完记得
writer.close(),否则 Excel 打开提示“文件已损坏”
小技巧:用 df.iloc[0:0].to_excel(writer, sheet_name="data", index=False) 先建空表头,再循环 df_chunk.to_excel(..., header=False) 写数据,避免重复表头。
日期、数字格式在 Excel 里显示异常?靠 openpyxl 手动设单元格类型
to_excel 不会自动识别 datetime64 或数值精度,导出后 Excel 常显示为长数字串(如 1712345678901)或科学计数法。根本原因是 Pandas 把它们当普通 object 写进 Excel,没设单元格格式。
修复方法:导出后用 openpyxl 加载工作簿,遍历列设格式:
from openpyxl import load_workbook
wb = load_workbook("output.xlsx")
ws = wb.active
for cell in ws["B"]: # 假设 B 列是日期
cell.number_format = "yyyy-mm-dd"
for cell in ws["C"]: # 假设 C 列是金额
cell.number_format = "#,##0.00"
wb.save("output.xlsx")- 日期列优先转成
pd.to_datetime()再导出,不然openpyxl无法正确识别 - 数字列用
df["col"] = df["col"].round(2)预处理,避免浮点误差影响格式设置 - 别在
to_excel里用float_format,它只影响数值显示,不改底层存储格式
真正麻烦的不是代码怎么写,而是不同数据库返回的 datetime 类型不一致(比如 MySQL 的 datetime 和 SQLite 的字符串),得在读取后统一用 pd.to_datetime 归一化,否则后面格式设置全失效。


















