You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:15:33