簡體   English   中英

用 pandas DataFrame 替換 mysql 數據庫表中的行

[英]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)

編譯方法歸功於https://stackoverflow.com/a/11762400/1919794

直到這個版本(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.

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