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