[英]UnicodeEncodeError when using pandas method to_sql on a dataframe with unicode column names
[英]to_sql() method of pandas sends primary key column as NULL even if the column is not present in dataframe
我想在Snowflake數據庫表中插入一個數據框。 數據庫有像id
這樣的列,它是一個primary_key
和event_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.