
Pandas DataFrame 中的 datetime64 类型列在通过 executemany 插入 PostgreSQL 时,若目标列为 timestamp without time zone,可能因 psycopg2 的类型推断机制失败而报错;需显式转换为字符串或使用 psycopg2.extensions.TimestampFromTicks 等适配方式。
pandas dataframe 中的 datetime64 类型列在通过 `executemany` 插入 postgresql 时,若目标列为 `timestamp without time zone`,可能因 psycopg2 的类型推断机制失败而报错;需显式转换为字符串或使用 `psycopg2.extensions.timestampfromticks` 等适配方式。
该错误的核心在于:psycopg2 在执行 executemany(insert_query, data_to_insert) 时,并不会自动将 Python 的 datetime64[ns] 或 pd.Timestamp 对象映射为 PostgreSQL 的 TIMESTAMP 类型,尤其当数据源自 epoch 时间戳转换后未彻底“脱敏”(如仍含纳秒精度、时区信息残留或内部表示异常)时,底层可能将其序列化为整数(如 1689711600000000000),最终触发 DatatypeMismatch: ... expression is of type bigint。
尽管你的代码已调用 pd.to_datetime(..., unit='s') 将 int64 转为 datetime64[ns],且日志显示 dtypes 正确,但问题仍存在——这是因为 df.to_records(index=False).tolist() 会将 datetime64[ns] 元素转为 numpy.datetime64 对象,而 psycopg2 默认不支持该类型直接绑定,部分版本甚至会退化为整数时间戳(纳秒级整数),导致 PostgreSQL 接收 bigint 而非 timestamp。
✅ 正确解法不是“再转一次字符串”,而是确保传入 executemany 的每个 timestamp 值是标准 Python datetime.datetime 对象(无时区、无 numpy 依赖):
from datetime import datetime
import numpy as np
# 在 timestamp 列处理逻辑后,增加标准化转换
for col in timestamp_columns:
if col in df_for_insertion.columns:
# 先确保是 datetime64 类型
if pd.api.types.is_datetime64_any_dtype(df_for_insertion[col]):
# 去除时区(关键!),并转为原生 datetime(非 numpy)
df_for_insertion[col] = pd.to_datetime(
df_for_insertion[col],
utc=False,
errors='coerce'
).dt.tz_localize(None).dt.to_pydatetime()
⚠️ 注意事项:
- ❌ 避免使用
.dt.strftime('%Y-%m-%d %H:%M:%S')→ 这会转为str,虽可绕过类型错误,但丧失类型语义,且无法处理NaT(转为'NaT'字符串导致插入失败); - ✅ 必须调用
.dt.to_pydatetime():它将每个pd.Timestamp安全转为datetime.datetime,这是psycopg2原生支持的类型; - ✅ 对
NaT值,to_pydatetime()返回None,与 PostgreSQL 的NULL自然兼容; - ? 可选验证:插入前检查首几行数据类型:
sample = df_for_insertion.iloc[0] print(type(sample['occurence_timestamp'])) # 应输出 <class></class>
? 补充建议(提升健壮性):
- 在构造
data_to_insert前,对所有 timestamp 列做空值归一化:df_for_insertion = df_for_insertion.where(pd.notna(df_for_insertion), None)
- 若数据库列允许
NULL,确保None被正确传递(psycopg2已原生支持); - 使用
cursor.mogrify()调试单条记录的实际绑定值(开发阶段):sample_row = tuple(df_for_insertion.iloc[0]) print(cursor.mogrify(insert_query, sample_row).decode('utf-8'))
总结:类型不匹配的本质是 Python 数据容器(numpy/pandas)与 PostgreSQL 驱动(psycopg2)之间的类型契约未对齐。解决路径始终是——主动降维:将 pandas/numpy 时间类型,明确、干净地降级为标准库 datetime.datetime,而非依赖驱动自动推断。









