[英]REPLACE rows in mysql database table with pandas DataFrame
Python 版本 - 2.7.6
熊貓版 - 0.17.1
MySQLdb 版本 - 1.2.5
在我的數據庫 ( PRODUCT
) 中,我有一個表 ( XML_FEED
)。 表 XML_FEED 很大(數百萬條記錄)我有一個 pandas.DataFrame() ( PROCESSED_DF
)。 數據框有數千行。
現在我需要運行這個
REPLACE INTO TABLE PRODUCT.XML_FEED
(COL1, COL2, COL3, COL4, COL5),
VALUES (PROCESSED_DF.values)
題:-
有沒有辦法在熊貓中運行REPLACE INTO TABLE
? 我已經檢查pandas.DataFrame.to_sql()
但這不是我需要的。 我不喜歡閱讀 pandas 中的XML_FEED
表,因為它非常大。
隨着 pandas 0.24.0 的發布,現在有一種官方方法可以通過將自定義插入方法傳遞給to_sql
函數來實現這一點。
通過將此可調用對象傳遞給to_sql
,我能夠實現REPLACE INTO
的行為:
def mysql_replace_into(table, conn, keys, data_iter):
from sqlalchemy.dialects.mysql import insert
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.sql.expression import Insert
@compiles(Insert)
def replace_string(insert, compiler, **kw):
s = compiler.visit_insert(insert, **kw)
s = s.replace("INSERT INTO", "REPLACE INTO")
return s
data = [dict(zip(keys, row)) for row in data_iter]
conn.execute(table.table.insert(replace_string=""), data)
你會像這樣傳遞它:
df.to_sql(db, if_exists='append', method=mysql_replace_into)
或者,如果你想要INSERT... ON DUPLICATE KEY UPDATE...
的行為,你可以使用這個:
def mysql_replace_into(table, conn, keys, data_iter):
from sqlalchemy.dialects.mysql import insert
data = [dict(zip(keys, row)) for row in data_iter]
stmt = insert(table.table).values(data)
update_stmt = stmt.on_duplicate_key_update(**dict(zip(stmt.inserted.keys(),
stmt.inserted.values())))
conn.execute(update_stmt)
直到這個版本(0.17.1)
我無法在熊貓中找到任何直接的方法來做到這一點。 我報告了一個相同的功能請求。 我在我的項目中使用MySQLdb
執行一些查詢然后使用DataFrame.to_sql(if_exists='append')
認為
1) product_id 是我在表 PRODUCT 中的主鍵
2) feed_id 是我在表 XML_FEED 中的主鍵。
簡易版
import MySQLdb
import sqlalchemy
import pandas
con = MySQLdb.connect('localhost','root','my_password', 'database_name')
con_str = 'mysql+mysqldb://root:my_password@localhost/database_name'
engine = sqlalchemy.create_engine(con_str) #because I am using mysql
df = pandas.read_sql('SELECT * from PRODUCT', con=engine)
df_product_id = df['product_id']
product_id_str = (str(list(df_product_id.values))).strip('[]')
delete_str = 'DELETE FROM XML_FEED WHERE feed_id IN ({0})'.format(product_id_str)
cur = con.cursor()
cur.execute(delete_str)
con.commit()
df.to_sql('XML_FEED', if_exists='append', con=engine)# you can use flavor='mysql' if you do not want to create sqlalchemy engine but it is depreciated
請注意:- REPLACE [INTO]
語法允許我們將一行INSERT
表中,除非發生UNIQUE KEY
(包括PRIMARY KEY
)違規,舊行在新 INSERT 之前被刪除,因此沒有違規。
我需要一個通用的解決方案來解決這個問題,所以我以 shiva 的答案為基礎——也許它會對其他人有所幫助。 這在您從 MySQL 數據庫(整個或過濾的)中獲取一個表,更新/添加一些行,並希望使用df.to_sql()
執行REPLACE INTO
語句的情況下很有用。
它找到表的主鍵,使用 pandas 數據幀中的所有鍵對 MySQL 表執行刪除語句,然后將數據幀插入 MySQL 表。
def to_sql_update(df, engine, schema, table):
df.reset_index(inplace=True)
sql = ''' SELECT column_name from information_schema.columns
WHERE table_schema = '{schema}' AND table_name = '{table}' AND
COLUMN_KEY = 'PRI';
'''.format(schema=schema, table=table)
id_cols = [x[0] for x in engine.execute(sql).fetchall()]
id_vals = [df[col_name].tolist() for col_name in id_cols]
sql = ''' DELETE FROM {schema}.{table} WHERE 0 '''.format(schema=schema, table=table)
for row in zip(*id_vals):
sql_row = ' AND '.join([''' {}='{}' '''.format(n, v) for n, v in zip(id_cols, row)])
sql += ' OR ({}) '.format(sql_row)
engine.execute(sql)
df.to_sql(table, engine, schema=schema, if_exists='append', index=False)
如果你使用 to_sql 你應該能夠定義它,以便你替換存在的值,所以對於名為“mydb”的表和名為“df”的數據框,你將使用:
df.to_sql(mydb,if_exists='replace')
如果它們已經存在,那應該替換值,但我不能 100% 確定這是否是您要查找的內容。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.