首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Psycopg2无法将numpy nans写入postgresql表:类型为double精度的输入语法无效:"“

Psycopg2无法将numpy nans写入postgresql表:类型为double精度的输入语法无效:"“
EN

Stack Overflow用户
提问于 2020-09-30 13:42:49
回答 5查看 1.8K关注 0票数 1

我有一个小的pyhton代码,它用一个(或多个) nans构建一个dataframe,然后用psycopg2模块使用copy_from函数将它写到postgres数据库中。下面是:

代码语言:javascript
运行
复制
table_name = "test"
df = pd.DataFrame([[1.0, 2.0], [3.0, np.nan]], columns=["VALUE0", "VALUE1"], index=pd.date_range("2000-01-01", "2000-01-02"))
database = "xxxx"
user = "xxxxxxx"
password = "xxxxxx"
host = "127.0.0.1"
port = "xxxxx"
def nan_to_null(f,
                _NULL=psycopg2.extensions.AsIs('NULL'),
                _NaN=np.NaN,
                _Float=psycopg2.extensions.Float):
    if f != f:
        return _NULL
    else:
        return _Float(f)
psycopg2.extensions.register_adapter(float, nan_to_null)
psycopg2.extensions.register_adapter(np.float, nan_to_null)
psycopg2.extensions.register_adapter(np.float64, nan_to_null)
with psycopg2.connect(database=database,
                      user=user,
                      password=password,
                      host=host,
                      port=port) as conn:
    try:
        with conn.cursor() as cur:
            cmd = "CREATE TABLE {} (TIMESTAMP timestamp PRIMARY KEY NOT NULL, VALUE0 FLOAT, VALUE1 FLOAT)"
            cur.execute(sql.SQL(cmd).format(sql.Identifier(table_name)))
            buffer = StringIO()
            df.to_csv(buffer, index_label='TIMESTAMP', header=False)
            buffer.seek(0)
            cur.copy_from(buffer, table_name, sep=",")
        conn.commit()
    except Exception as e:
        conn.rollback()
        logging.error(traceback.format_exc())
        raise e

问题在于,psycopg2未能将nan转换为posgres,尽管我使用了以下技巧:如何将numpy NaN对象转换为SQL空值? ( nan_to_null函数)。我无法使它工作,它抛出以下异常:

代码语言:javascript
运行
复制
psycopg2.errors.InvalidTextRepresentation: invalid input syntax for type double precision: ""
CONTEXT:  COPY test, line 2, column value1: ""

我在windows 10上使用python3.8,其中包含anaconda 3、psycopg2 v2.8.5和postgres v12.3。谢谢!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2020-09-30 14:16:18

问题是copy_from的使用。来自文档

目前,Python和PostgreSQL类型之间没有在副本上提供任何适配:.

这样你的适配器就不起作用了。

更新--可能的解决方案:

熊猫在保存到CSV时更改NaN值的格式

见@cs95 95答复。

票数 1
EN

Stack Overflow用户

发布于 2020-10-01 09:32:51

我在这里放了同样的代码,并更新了禤浩焯Klaver的解。更改的行是:

Df.to_csv(缓冲区,索引_标签=‘时间戳’,header=False,na_rep='NaN')

我们在to_csv函数中添加了na_rep='NaN‘。不需要用另一行代码替换nans。用'NULL‘替换不起作用。

代码语言:javascript
运行
复制
import psycopg2, logging, numpy as np, pandas as pd
from psycopg2 import sql
import traceback
from io import StringIO


if __name__ == '__main__':
    table_name = "test"
    df = pd.DataFrame([[1.0, 2.0], [3.0, np.nan]], columns=["VALUE0", "VALUE1"], index=pd.date_range("2000-01-01", "2000-01-02"))

    database = "xxxxxx"
    user = "xxxxx"
    password = "xxxxxx"
    host = "127.0.0.1"
    port = "xxxxxx"

    with psycopg2.connect(database=database,
                          user=user,
                          password=password,
                          host=host,
                          port=port) as conn:
        try:
            with conn.cursor() as cur:
                #Creating a new table test
                cmd = "CREATE TABLE {} (TIMESTAMP timestamp PRIMARY KEY NOT NULL, VALUE0 FLOAT, VALUE1 FLOAT);"
                cur.execute(sql.SQL(cmd).format(sql.Identifier(table_name)))
                #Writting content
                buffer = StringIO()
                df.to_csv(buffer, index_label='TIMESTAMP', header=False, na_rep='NaN')
                buffer.seek(0)
                cur.copy_from(buffer, table_name, sep=",")

                #Reading the table content
                cmd = "SELECT * FROM {};"
                cur.execute(sql.SQL(cmd).format(sql.Identifier(table_name)))
                test_data = pd.DataFrame(cur.fetchall())
                print(test_data)
                print(type(test_data.loc[1, 2]))

                #Deleting the test table
                cmd = "DROP TABLE {};"
                cur.execute(sql.SQL(cmd).format(sql.Identifier(table_name)))
            conn.commit()
        except Exception as e:
            conn.rollback()
            logging.error(traceback.format_exc())
            raise e

打印结果表明,nan被很好地解释并存储在DB中。

票数 2
EN

Stack Overflow用户

发布于 2020-09-30 14:05:31

似乎您正在插入空字符串而不是空值,您可以使用以下SQL代码轻松地再现您的错误:

代码语言:javascript
运行
复制
CREATE TABLE test(
   x FLOAT
);
INSERT INTO test(x) VALUES ('');
-- ERROR: invalid input syntax for type double precision: "" Position: 29

另一方面,NaN可以安全地插入到PostgreSQL中:

代码语言:javascript
运行
复制
INSERT INTO test(x) VALUES ('NaN');

请注意,PostgreSQL浮点支持与IEEE754标准略有不同,因为PostresSQL需要所有的值都是可排序的,才能始终如一地构建索引。因此,NaN大于或等于任何其他数字,包括PostgreSQL中的自身。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64138893

复制
相关文章

相似问题

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