如何使用 pandas sqlalchemy 和 psycopg2 处理 NaT

Posted

技术标签:

【中文标题】如何使用 pandas sqlalchemy 和 psycopg2 处理 NaT【英文标题】:How to handle NaTs with pandas sqlalchemy and psycopg2 【发布时间】:2017-05-04 18:31:50 【问题描述】:

我有一个带有类似 NaT 的数据框,这给了我一个 DataError: (psycopg2.DataError) invalid input syntax for type timestamp: "NaT":当我尝试将值插入到 postgres db 中时

数据框

from sqlalchemy import MetaData
from sqlalchemy.dialects.postgresql import insert
import pandas as pd

tst_df = pd.DataFrame('colA':['a','b','c','a','z', 'q'],
                  'colB': pd.date_range(end=datetime.datetime.now() , periods=6),
                  'colC' : ['a1','b2','c3','a4','z5', 'q6'])
tst_df.loc[5, 'colB'] = pd.NaT



insrt_vals = tst_df.to_dict(orient='records')
engine = sqlalchemy.create_engine("postgresql://user:password@localhost/postgres")
connect = engine.connect()
meta = MetaData(bind=engine)
meta.reflect(bind=engine)
table = meta.tables['tstbl']
insrt_stmnt = insert(table).values(insrt_vals)

do_nothing_stmt  = insrt_stmnt.on_conflict_do_nothing(index_elements=['colA','colB'])

产生错误的代码

results = engine.execute(do_nothing_stmt)

DataError: (psycopg2.DataError) invalid input syntax for type timestamp: "NaT"
LINE 1: ...6-12-18T09:54:05.046965'::timestamp, 'z5'), ('q', 'NaT'::tim...

here 提到的一种可能性是将 NaT 替换为 None,但正如之前的作者所说,这似乎有点 hackish。

sqlachemy  1.1.4
pandas  0.19.1
psycopg2 2.6.2 (dt dec pq3 ext lo64)

【问题讨论】:

NaT 只是一个特殊变量,定义为表示和处理丢失的时间。它类似于 NaN 的浮点数。我不指望它会在您尝试放置的每个地方都播放得很好。我同意,用None 替换似乎很骇人听闻……但我没有看到一种不那么骇人听闻的方法。 【参考方案1】:

您是否尝试过使用 Pandas to_sql 方法?

它适用于我的 mysql 数据库(我认为它也适用于 PostgreSQL):

In [50]: tst_df
Out[50]:
  colA                       colB colC
0    a 2016-12-14 19:11:36.045455   a1
1    b 2016-12-15 19:11:36.045455   b2
2    c 2016-12-16 19:11:36.045455   c3
3    a 2016-12-17 19:11:36.045455   a4
4    z 2016-12-18 19:11:36.045455   z5
5    q                        NaT   q6

In [51]: import pymysql
    ...: import sqlalchemy as sa
    ...:

In [52]:

In [52]: db_connection = 'mysql+pymysql://user:password@mysqlhost/db_name'
    ...:

In [53]: engine = sa.create_engine(db_connection)
    ...: conn = engine.connect()
    ...:

In [54]: tst_df.to_sql('zzz', conn, if_exists='replace', index=False)

在 MySQL 方面:

mysql> select * from zzz;
+------+---------------------+------+
| colA | colB                | colC |
+------+---------------------+------+
| a    | 2016-12-14 19:11:36 | a1   |
| b    | 2016-12-15 19:11:36 | b2   |
| c    | 2016-12-16 19:11:36 | c3   |
| a    | 2016-12-17 19:11:36 | a4   |
| z    | 2016-12-18 19:11:36 | z5   |
| q    | NULL                | q6   |
+------+---------------------+------+
6 rows in set (0.00 sec)

不幸的是,我没有用于测试的 PostgreSQL

【讨论】:

不幸的是,我正在尝试附加on conflict 或在mysql的情况下ON DUPLICATE ..熊猫不支持

以上是关于如何使用 pandas sqlalchemy 和 psycopg2 处理 NaT的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Pandas 中使用 sqlalchemy 执行具有多个日期参数的 sql 存储过程

使用 SQLAlchemy 和 Pandas 插入数据 - Python

截断表不适用于 SQL Server sqlalchemy 引擎和 pandas

Pandas 和 SQLAlchemy:使用来自 engine.begin() 的连接时,带有 SQLAlchemy 2.0 fututre=True 的 df.to_sql() 会引发错误

想要使用 pandas 和 sqlalchemy 从查询是变量(不和谐用户名)的数据库中选择所有内容

无法在 ETL 过程中使用 Pandas 和 SQLAlchemy 将列名从 CSV 更改为 SQL Server DB