首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何正确地将NaT日期时间值插入到postgresql表中

如何正确地将NaT日期时间值插入到postgresql表中
EN

Stack Overflow用户
提问于 2020-10-19 21:47:11
回答 2查看 6.8K关注 0票数 6

我正在捆绑批量插入一个数据文件到我的postgres dB。我的dataframe中的某些列是日期类型,NaT为空值。这是PostgreSQL不支持的,我尝试用其他空类型标识替换NaT (使用熊猫),但在插入过程中不起作用。

我使用df = df.where(pd.notnull(df), 'None')替换了所有的NaT,例如由于数据类型问题而不断出现的错误。

代码语言:javascript
运行
复制
Error: invalid input syntax for type date: "None"
LINE 1: ...0,1.68757,'2022-11-30T00:29:59.679000'::timestamp,'None','20...

我的驱动程序和插入语句到postgresql dB:

代码语言:javascript
运行
复制
def execute_values(conn, df, table):
    """
    Using psycopg2.extras.execute_values() to insert the dataframe
    """
    # Create a list of tupples from the dataframe values
    tuples = [tuple(x) for x in df.to_numpy()]
    # Comma-separated dataframe columns
    cols = ','.join(list(df.columns))
    # SQL quert to execute
    query  = "INSERT INTO %s(%s) VALUES %%s" % (table, cols)
    cursor = conn.cursor()
    try:
        extras.execute_values(cursor, query, tuples)
        conn.commit()
    except (Exception, psycopg2.DatabaseError) as error:
        print("Error: %s" % error)
        conn.rollback()
        cursor.close()
        return 1
    print("execute_values() done")
    cursor.close()

有关我的dataframe的信息:在本例中,罪魁祸首仅为datetime列。

这通常是如何解决的?

EN

回答 2

Stack Overflow用户

发布于 2021-01-29 16:20:37

关于您原来的更新声明:

df = df.where(pd.notnull(df), 'None')

这里发生的是用字符串' None‘替换值,而不是用特殊的Python对象None替换值。然后在下面的insert语句中,尝试将字符串'None‘插入时间戳字段并引发错误。

有趣的是,你所期望的这个版本是可行的:

df = df.where(pd.notnull(df), None)

实际上,由于我不完全理解的原因,NaT值似乎不像预期的那样工作。(见下文示例)

但是,看起来起作用的是这样的语句(假设您将numpy导入为np):

df = df.replace({np.NaN: None})

因此,如果这样做,那么NaN和NaT值都将转换为Python,然后psycopg2 (或者任何其他db连接器)将正确地将这些值作为插入的SQL对待。

下面是一些示例代码来说明:

代码语言:javascript
运行
复制
import datetime as dt
import pandas as pd
import numpy as np
data = [
    ['one', 1.0, pd.NaT],
    ['two', np.NaN, dt.datetime(2019, 2, 2)],
    [None, 3.0, dt.datetime(2019, 3, 3)]
    ]
df = pd.DataFrame(data, columns=["Name", "Value", "Event_date"])

得到了我们的基本数据

代码语言:javascript
运行
复制
>>> df
   Name  Value Event_date
0   one    1.0        NaT
1   two    NaN 2019-02-02
2  None    3.0 2019-03-03

如前所述,由于某些原因,此更新将NaT保留在其中:

代码语言:javascript
运行
复制
>>> df.where(pd.notnull(df), None)
   Name Value Event_date
0   one   1.0        NaT
1   two  None 2019-02-02
2  None   3.0 2019-03-03

但是这个版本同时获得了NaNs和NaTs,并留下了预期的Nones:

代码语言:javascript
运行
复制
>>> df.replace({np.NaN: None})
   Name Value           Event_date
0   one   1.0                 None
1   two  None  2019-02-02 00:00:00
2  None   3.0  2019-03-03 00:00:00

接受的答案可能是“更好”的方式,如果你可以使用sqlalchemy来做你想做的事情,但是如果你要用艰苦的方式去做,这对我是有效的。

H/T到关于大熊猫问题的讨论获得这个答案的大部分细节。

票数 5
EN

Stack Overflow用户

发布于 2022-04-13 08:43:10

如果不能使用pandasto_sql方法,则可以用psycopg代替注册适配器

代码语言:javascript
运行
复制
import pandas as pd
from psycopg2.extensions import register_adapter, AsIs

# Register adapter for pandas NA type (e.g. null datetime or integer values)
# NOTE: Must use protected member, rather than pd.NA, as pd.NA is just defined as None
register_adapter(pd._libs.missing.NAType, lambda i: AsIs('NULL'))

然后,当您调用psycopg的任何execute方法时,它将自动将任何pd.NA值转换为PostgreSQL NULL值。

请注意,同样的原则也可以用于numpy NaN值:

代码语言:javascript
运行
复制
import numpy as np
from psycopg2.extensions import register_adapter, AsIs, Float

# Register adapter for np.nan
register_adapter(float, lambda f: AsIs('NULL') if np.isnan(f) else Float(f))
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64435497

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档