使用psycopg2查询数据后,导出xlsx如何保留正确数据格式?
问题描述
我用psycopg2查询数据库获取数据,需要直接写入.xlsx文件。之前用以下代码导出.csv完全正常:
with open("file_name.csv", "w") as file: csv_writer = writer(file) csv_writer.writerow(headers) csv_writer.writerows(data)
但每次要手动把.csv另存为.xlsx,想省去这一步。
尝试用pandas导出:
df = pandas.DataFrame(data, columns=headers) df.to_excel("file_name.xlsx")
结果所有数字都存成文本,得手动刷新单元格才能让Excel识别成数值;用openpyxl时情况好点,但日期列还是文本,同样要手动刷新才能识别为日期。
怀疑过是psycopg2读取数据的问题,但.csv导出没问题,应该是对两种文件格式的差异理解不够。请问怎么直接导出为.xlsx并保留所有正确格式?
解决方案
1. 用pandas自动映射数据库类型(推荐)
直接通过sqlalchemy连接数据库读取数据,pandas会自动映射PostgreSQL的类型到对应Python类型,导出Excel时就能保留正确格式,无需手动转换:
import pandas as pd from sqlalchemy import create_engine # 替换为你的数据库连接信息 engine = create_engine('postgresql+psycopg2://用户名:密码@主机:端口/数据库名') # 直接执行查询并读取到DataFrame df = pd.read_sql_query("SELECT * FROM 你的表名", engine) # 导出Excel,index=False去掉默认的行索引 df.to_excel("file_name.xlsx", index=False)
如果已经用psycopg2获取了data和headers,可以手动指定列类型转换:
import pandas as pd df = pd.DataFrame(data, columns=headers) # 转换数值列(替换为你的数值列名) numeric_cols = ['金额', '数量'] df[numeric_cols] = df[numeric_cols].apply(pd.to_numeric, errors='coerce') # 转换日期列(替换为你的日期列名和格式) date_cols = ['创建时间'] df[date_cols] = df[date_cols].apply(pd.to_datetime, format='%Y-%m-%d', errors='coerce') df.to_excel("file_name.xlsx", index=False)
errors='coerce'会把无法转换的值设为NaN,可根据需求调整。
2. 用openpyxl手动设置单元格格式
如果坚持用openpyxl,需要在写入数据时为单元格指定格式,同时确保psycopg2返回的是原生Python类型(而非字符串):
from openpyxl import Workbook from openpyxl.styles import numbers from datetime import datetime wb = Workbook() ws = wb.active # 写入表头 ws.append(headers) # 写入数据并设置格式 for row in data: ws.append(row) row_num = ws.max_row for col_idx, cell_value in enumerate(row, 1): cell = ws.cell(row=row_num, column=col_idx) # 识别数值类型并设置格式 if isinstance(cell_value, (int, float)): cell.number_format = numbers.FORMAT_NUMBER # 识别日期类型并设置格式 elif isinstance(cell_value, datetime): cell.number_format = numbers.FORMAT_DATE_XLSX15 # yyyy-mm-dd格式 # 若psycopg2返回的是日期字符串,先转换再设置格式 elif headers[col_idx-1] == '创建时间': cell.value = datetime.strptime(cell_value, '%Y-%m-%d') cell.number_format = numbers.FORMAT_DATE_XLSX15 wb.save("file_name.xlsx")
3. 确保psycopg2返回原生类型
psycopg2默认会把PostgreSQL的数值、日期类型转为Python原生类型,但要注意:
- 查询语句不要把数值/日期强制转成字符串(比如避免
CAST(金额 AS VARCHAR)) - 不要自定义会破坏类型映射的
cursor_factory,默认cursor即可
内容的提问来源于stack exchange,提问作者S7ewie
相关产品推荐
相关产品推荐

