【问题标题】:How do I convert numpy NaN objects to SQL nulls?如何将 numpy NaN 对象转换为 SQL 空值?
【发布时间】:2022-04-28 08:14:22
【问题描述】:

我有一个要插入 SQL 数据库的 Pandas 数据框。我直接使用 Psycopg2 与数据库对话,而不是 SQLAlchemy,所以我不能使用 Pandas 内置的 to_sql 函数。几乎所有东西都按预期工作,除了 numpy np.NaN 值被转换为文本作为 NaN 并插入数据库的事实。它们确实应该被视为 SQL 空值。

因此,我正在尝试制作一个自定义适配器来将 np.NaN 转换为 SQL null,但我尝试的所有操作都会导致在数据库中插入相同的 NaN 字符串。

我目前正在尝试的代码是:

def adapt_nans(null):
    a = adapt(None).getquoted()
    return AsIs(a)

register_adapter(np.NaN, adapt_nans)

我在这个主题上尝试了许多变体,但都没有成功。

【问题讨论】:

  • 就我个人而言,我会说 NaN 应该被转换为 NULL,因为它们根本不是一回事,但我可以想象我的上下文猜猜这可能是有道理的。我会使用BEFORE INSERT OR UPDATE ... FOR EACH ROW ... 触发器来转换它们。
  • 我确实理解 NaN 和 NULL 之间的一般差异,但是,在这种特殊情况下,它们确实是同一回事。数据从平面文件读入数据帧,Pandas 在缺少数据的地方插入一个 NaN。

标签: python postgresql psycopg2


【解决方案1】:

我之前尝试的代码失败了,因为它假定 np.Nan 是它自己的类型,而它实际上是一个浮点数。以下代码courtesy of Daniele Varrazzo on the psycopg2 mailing list 正确完成了这项工作。

def nan_to_null(f,
        _NULL=psycopg2.extensions.AsIs('NULL'),
        _Float=psycopg2.extensions.Float):
    if not np.isnan(f):
        return _Float(f)
    return _NULL

 psycopg2.extensions.register_adapter(float, nan_to_null)

【讨论】:

  • 该函数似乎不适用于 np.float64。不知道为什么。将 if f is not _NaN: 更改为 if not np.isnan(f): 修复了它。否则完美!
  • @JensdeBruijn 我想知道 float64 的 NaN 类型是否与常规浮点的 NaN 类型不同。
  • 我也很惊讶。如果不是这样,它会是熊猫吗?使用上面的语句,我的错误得到了修复。我只是想把它作为一个选项来展示是否有人遇到了同样的问题
  • 我不得不使用@JensdeBruijn 提出的小修复,现在效果很好
  • 也必须使用小修复。我提出了修改建议。
【解决方案2】:

此答案是Gregory Arenius's Answer 的替代版本。我已经通过简单地检查值是否等于自身来替换条件语句来处理任何 Nan 值。

def nan_to_null(f,
         _NULL=psycopg2.extensions.AsIs('NULL')
         _Float=psycopg2.extensions.Float)):
    if f != f:
        return _NULL
    else:
         return _Float(f)

 psycopg2.extensions.register_adapter(float, nan_to_null)

如果你检查一个 nan 值是否等于它自己,你会得到 False。 Stephen Canon's answer 中详细解释了其工作原理背后的原因。

【讨论】:

    【解决方案3】:

    我认为最简单的方法是:

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

    然后None 被“翻译”为NULL,当导入到 Postgres 时。

    【讨论】:

      【解决方案4】:

      如果您尝试将 Pandas 数据帧数据插入 PostgreSQL 并收到NaN 的错误,您所要做的就是:

      import psycopg2
      
      output_df = output_df.fillna(psycopg2.extensions.AsIs('NULL'))
      
      #Now insert output_df data in the table
      

      【讨论】:

        猜你喜欢
        • 2018-01-07
        • 1970-01-01
        • 1970-01-01
        • 2019-09-10
        • 2021-07-06
        • 2020-06-13
        • 2021-03-27
        • 2019-05-10
        • 1970-01-01
        相关资源
        最近更新 更多