簡體   English   中英

pandas 的 to_sql() 方法將主鍵列作為 NULL 發送,即使該列不存在於 dataframe 中

[英]to_sql() method of pandas sends primary key column as NULL even if the column is not present in dataframe

我想在Snowflake數據庫表中插入一個數據框。 數據庫有像id這樣的列,它是一個primary_keyevent_id這是一個integer字段,它也是nullable

我使用SQLAlchemy創建了一個declarative_base() class ,如下所示 -

class AccountUsageLoginHistory(Base):

    __tablename__ = constants.TABLE_ACCOUNT_USAGE_LOGIN_HISTORY
    __table_args__ = {
        'extend_existing':True,
        'schema' : os.environ.get('SCHEMA_NAME_AUDITS')
    }

    id = Column(Integer, Sequence('id_account_usage_login_history'), primary_key=True)
    event_id = Column(Integer, nullable=True)

上述 class 在Snowflake數據庫中創建了一個表。

我有一個只有一列event_id的數據框。

當我嘗試使用 pandas to_sql()方法插入數據時,Snowflake 返回如下所示的錯誤 -

snowflake.connector.errors.ProgrammingError: 100072 (22000): 01991f2c-0be5-c903-0000-d5e5000c6cee: NULL result in a non-nullable column

此錯誤是由 snowflake 生成的,因為to_sql()附加了一個列id ,並且該列的每一行的值都設置為null

dataframe.to_sql(table_name, self.engine, index=False, method=pd_writer, if_exists="append")

將此視為案例 1 -

我試圖直接對雪花運行插入查詢 -

insert into "SFOPT_TEST"."AUDITS"."ACCOUNT_USAGE_LOGIN_HISTORY" (ID, EVENT_ID) values(NULL, 33)

上面的查詢返回了同樣的錯誤 -

NULL result in a non-nullable column

上面的查詢是to_sql()方法可能執行的操作。

將此視為案例 2 -

我還嘗試通過執行下面所述的查詢來插入一行 -

insert into "SFOPT_TEST"."AUDITS"."ACCOUNT_USAGE_LOGIN_HISTORY" (EVENT_ID) values(33)

現在,這個特定的查詢已通過將數據插入表中而成功執行,並且它還為列id自動生成了值。

如何使to_sql()方法使用案例 2

請注意pandas.DataFrame.to_sql()有默認參數index=True這意味着它會在插入數據時添加一個額外的列(df.index)。

一些數據庫如 PostgreSQL 有一個數據類型serial允許你用遞增的數字順序填充列。

Snowflake DB 沒有這個概念,而是有其他方法來處理它:

第一個選項:您可以使用CREATE SEQUENCE語句並直接在數據庫中創建一個序列 - 這里是關於這個主題的官方文檔。 這種方法的缺點是您需要將 DataFrame 轉換為正確的 SQL 語句:

數據庫准備部分:

CREATE OR REPLACE SEQUENCE schema.my_sequence START = 1 INCREMENT = 1;
CREATE OR REPLACE TABLE schema.my_table (i bigint, b text);

您需要將 DataFrame 轉換為 Snowflake 的INSERT語句並使用schema.my_sequence.nextval獲取下一個 ID 值

INSERT INTO schema.my_table VALUES
(schema.my_sequence.nextval, 'string_1'),
(schema.my_sequence.nextval, 'string_2');

結果將是:

i b
1 string_1
2 string_2

請注意,這種方法有一些限制,您需要確保以這種方式執行的每個插入語句都會成功,因為調用schema.my_sequence.nextval而不插入它意味着會有間隙數字。 為了避免它,你可以有一個單獨的腳本來檢查當前插入是否成功,如果不成功,它將通過調用重新創建序列:

REPLACE SEQUENCE schema.my_sequence start = (SELECT max(i) FROM schema.my_table) increment = 1;

替代選項:您需要創建一個額外的 function 來運行 SQL 以獲得您之前插入的最后一個 i 。

SELECT max(i) AS max_i FROM schema.my_table;

然后在運行to_sql()之前更新 DataFrame 中的index

df.index = range(max_i+1, len(df)+max_i+1)

這將確保您的 DataFrame 索引在您的表中繼續。 完成后,您可以使用

df.to_sql(index_label='i', name='my_table', con=connection_object)

它將使用您的索引作為您插入的列之一,允許您維護表中的唯一索引。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM