将带有浮点值的 pandas 数据帧插入到 Oracle 中

Inserting pandas dataframe with float values into Oracle

提问人:Justin Mathew 提问时间:2/8/2023 最后编辑:DataJanitorJustin Mathew 更新时间:11/22/2023 访问量:1719

问:

我可以从 pandas 数据帧将整数、字符串等正常值插入 Oracle 中,但是当我尝试浮点类型值时,sqlalchemy 给出以下错误

sqlalchemy.exc.ArgumentError: Oracle FLOAT types use 'binary precision', which does not convert cleanly from decimal 'precision'.  Please specify this type with a separate Oracle variant, such as Float(precision=53).with_variant(oracle.FLOAT(binary_precision=176), 'oracle'), so that the Oracle specific 'binary_precision' may be specified accurately.

这是完整的源代码

import pandas as pd
import os
import sqlalchemy as sa
from sqlalchemy import text
from sqlalchemy.dialects import oracle


oracle_db = sa.create_engine('oracle://username:password@instance/?service_name=MBCDFE')
conn = oracle_db.connect()
df = pd.DataFrame({
    #"column1": [1, 1, 1], #- inserting into DB works with just numbers
    "column1": [1.2, 1.2, 1.2],
    "column2": ["a", "bb", "c"],
    "column3": ["K", "L", "M"]
})

df.to_sql("python", conn, if_exists="replace", index=True)
conn.commit()
conn.close()

任何帮助将不胜感激。非常感谢。

python pandas 数据帧 sqlalchemy cx-oracle

评论

2赞 Ian Thompson 2/8/2023
检查文档的底部。它们引用以及如何指定列的 dtype。您可以在此处找到更多信息。sqlalchemy.typessqlalchemy.types.Float
2赞 Justin Mathew 2/8/2023
@IanThompson - 非常感谢,绝对是正确的解决方案。但是,不确定当具有 100 多个列和不同类型的列的 DataFrame 时,放置此配置有多容易。我们仍然可以这样做,但如果 to_sql() 接受从 PD 列数据类型到 Oracle 类型的某种映射,而不是显式指定每个列的类型,那会更容易。无论如何,再次感谢你。
0赞 Ian Thompson 2/9/2023
您可以查看当前数据类型的用途,并查看哪些数据类型需要映射到 Oracle 类型。获得映射后,可以遍历序列和映射到列的 Oracle 类型。我没有 Oracle 连接,所以无法真正测试。df.dtypes.unique()df.dtypesmap

答:

-1赞 Inna Nikolenko 11/21/2023 #1

要使 Oracle 了解数字是浮点格式,您需要将其转换为文本格式并将点替换为逗号。在 Oracle 中以 NUMBER 格式的表中,它将被很好地添加。

要修改您的号码,您可以执行以下操作:

df["column1"] = df["column1"].astype(str).str.replace('.', ',')

如果有几列包含浮点数据,则必须分别对每一列执行此方法。

评论

0赞 Parfait 11/22/2023
你能引用关于这个解决方案的文档吗?对于像美国这样使用句点而不是逗号作为十进制数字的区域设置,这将如何工作?
-1赞 Artem Kotelevych 11/22/2023 #2

您遇到的错误是由于使用 SQLAlchemy 时处理 Pandas 和 Oracle 之间的数据类型时存在差异。Oracle 对 FLOAT 类型使用“二进制精度”,这与 Pandas 中使用的十进制精度不直接兼容。以下是解决此问题的方法:

在 to_sql中使用 dtype:在调用 to_sql 方法时为 DataFrame 列指定适当的数据类型。可以使用 sqlalchemy.types.Float 根据 Oracle 的要求以二进制精度定义数据类型。

下面是修改后的代码片段:

from sqlalchemy.types import Float

df.to_sql(
    "python",
    conn,
    if_exists="replace",
    index=True,
    dtype={
        "column1": Float(binary_precision=53),
        # Define other data types for other columns if necessary
    }
)

在本例中,Float(binary_precision=53) 定义 column1 的数据类型,其二进制精度适用于 Oracle。

数据一致性检查:确保 DataFrame 中的数据与要定义的数据类型真正匹配。在本例中,column1 应包含可表示为 FLOAT 的值。

提交事务:您正确地使用 conn.commit() 来提交事务。这对于确保更改保存在数据库中非常重要。

资源管理:使用上下文管理器来处理连接可以更安全,以确保即使发生错误也会关闭连接。

with oracle_db.connect() as conn:
    df.to_sql("python", conn, ...)
    conn.commit()

尝试将这些更改合并到代码中,然后再次运行。这应该有助于解决通过 Pandas 和 SQLAlchemy 将浮点类型数据插入 Oracle 的问题。