Snowflake pandas pd_writer 用 NULL 写出表

Posted

技术标签:

【中文标题】Snowflake pandas pd_writer 用 NULL 写出表【英文标题】:Snowflake pandas pd_writer writes out tables with NULLs 【发布时间】:2020-12-01 20:36:23 【问题描述】:

我有一个 Pandas 数据框,我正在使用 SQLAlchemy 引擎和 to_sql 函数将其写入 Snowflake。它工作正常,但由于某些雪花限制,我必须使用 chunksize 选项。这对于较小的数据帧也很好。但是,一些数据帧有 500k+ 行,并且每个块有 15k 条记录,完成对 Snowflake 的写入需要很长时间。

我做了一些研究,发现了 Snowflake 提供的 pd_writer 方法,显然它加载数据帧的速度要快得多。我的 Python 脚本完成得更快,我看到它创建了一个包含所有正确列和正确行数的表,但每一行中每一列的值都是 NULL。

我认为这是NaNNULL 的问题,并尽一切可能将NaNs 替换为None,虽然它在数据框中进行了替换,但当它到达表格时,一切都变成了NULL。

如何使用pd_writer 将这些巨大的数据帧正确写入雪花?有没有可行的替代方案?

编辑:按照克里斯的回答,我决定尝试使用官方示例。这是我的代码和结果集:

import os
import pandas as pd
from snowflake.sqlalchemy import URL
from sqlalchemy import create_engine
from snowflake.connector.pandas_tools import write_pandas, pd_writer


def create_db_engine(db_name, schema_name):
    return create_engine(
        URL(
            account=os.environ.get("DB_ACCOUNT"),
            user=os.environ.get("DB_USERNAME"),
            password=os.environ.get("DB_PASSWORD"),
            database=db_name,
            schema=schema_name,
            warehouse=os.environ.get("DB_WAREHOUSE"),
            role=os.environ.get("DB_ROLE"),
        )
    )


def create_table(out_df, table_name, idx=False):
    engine = create_db_engine("dummy_db", "dummy_schema")
    connection = engine.connect()

    try:
        out_df.to_sql(
            table_name, connection, if_exists="append", index=idx, method=pd_writer
        )

    except ConnectionError:
        print("Unable to connect to database!")

    finally:
        connection.close()
        engine.dispose()

    return True


df = pd.DataFrame([("Mark", 10), ("Luke", 20)], columns=["name", "balance"])

print(df.head)

create_table(df, "dummy_demo_table")

代码运行良好,没有任何问题,但是当我查看创建的表时,它全是 NULL。再次。

【问题讨论】:

【参考方案1】:

事实证明,文档(可以说是 Snowflake 的弱点)与现实不同步。这是真正的问题:https://github.com/snowflakedb/snowflake-connector-python/issues/329。它只需要列名中的单个字符为大写即可。

我的解决方法是在调用 to_sql 之前简单地执行:df.columns = map(str.upper, df.columns)

【讨论】:

上帝保佑你@CodingInCircles!找了3天找到了解决办法。 效果很好。谢谢。 @= 我用雪花见过几次 df.columns = df.columns.str.upper() 也可以,顺便说一句。【参考方案2】:

我也遇到过同样的问题,不要绝望,有解决方案。当您在雪花中创建表时,从雪花工作表或雪花环境中,它以大写命名对象以及所有列和约束。但是,当您使用数据框从 Python 创建表时,将按照您在数据框中指定的确切情况创建对象。在您的情况下,它是 columns=['name', 'balance'])。因此,当插入发生时,它会在雪花中查找所有大写列名并且找不到它,它会执行插入但将您的 2 列设置为 null,因为这些列被创建为可为空。

解决此问题的最佳方法是在数据框中以大写形式创建列,columns=['NAME', 'BALANCE'])。

我认为这是雪花应该解决和修复的问题,因为它不是预期的行为。

即使您尝试从包含空值的表中进行选择,您也会收到错误,例如: 从 dummy_demo_table 中选择名称、余额

您可能会收到如下错误, SQL 编译错误:位置 7 处的错误第 1 行无效标识符 'name'

但以下内容将起作用 SELECT * from dummy_demo_table

【讨论】:

【参考方案3】:

我假设您已经查看了documentation 并看到了这个示例代码:

import pandas
from snowflake.connector.pandas_tools import pd_writer

# Create a DataFrame containing data about customers
df = pandas.DataFrame([('Mark', 10), ('Luke', 20)], columns=['name', 'balance'])

# Specify that the to_sql method should use the pd_writer function
# to write the data from the DataFrame to the table named "customers"
# in the Snowflake database.
df.to_sql('customers', engine, index=False, method=pd_writer)

如果没有您的 Python 代码示例和一些匹配的虚拟数据,我认为我们无法为您提供除此之外的帮助,以便我们可以进一步调查。我的建议是首先让上面的示例工作,然后在不包含任何 NaN 的较小数据帧上测试该过程,然后从那里开始增长。

【讨论】:

我已经更新了我的问题。请看一下,让我知道是否有什么让你跳出来的东西。谢谢你的帮助:)

以上是关于Snowflake pandas pd_writer 用 NULL 写出表的主要内容,如果未能解决你的问题,请参考以下文章

Snowflake Python Pandas 连接器 - 使用 fetch_pandas_all 的未知错误

Snowflake pandas pd_writer 用 NULL 写出表

如何从 Snowflake SQL 查询创建 PySpark pandas-on-Spark DataFrame?

如何在 Snowflake 中找到我的 Snowflake 账单?

Snowflake 是不是支持索引?

sqitch init snowflake 无法确定 Snowflake 账户名