如何使用Pandas数据帧对db表的现有行执行更新?

2024-06-09 08:30:47 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图查询MySql数据库表的一个子集,将结果输入Pandas数据框,更改一些数据,然后将更新的行写回同一个表。我的表大小约为1毫米行,我要更改的行数相对较少(<;50000),因此将整个表带回来并执行df.to_sql(tablename,engine, if_exists='replace')不是一个可行的选择。有没有一种简单的方法可以更新已更改的行,而不必遍历数据帧中的每一行?

我知道这个项目试图模拟“upsert”工作流,但它似乎只完成插入新的非重复行的任务,而不是更新现有行的部分:

GitHub Pandas-to_sql-upsert

以下是我试图在更大范围内完成的工作的概要:

import pandas as pd
from sqlalchemy import create_engine
import threading

#Get sample data
d = {'A' : [1, 2, 3, 4], 'B' : [4, 3, 2, 1]}
df = pd.DataFrame(d)

engine = create_engine(SQLALCHEMY_DATABASE_URI)

#Create a table with a unique constraint on A.
engine.execute("""DROP TABLE IF EXISTS test_upsert """)
engine.execute("""CREATE TABLE test_upsert (
                  A INTEGER,
                  B INTEGER,
                  PRIMARY KEY (A)) 
                  """)

#Insert data using pandas.to_sql
df.to_sql('test_upsert', engine, if_exists='append', index=False)

#Alter row where 'A' == 2
df_in_db.loc[df_in_db['A'] == 2, 'B'] = 6

现在我想把df_in_db写回我的'test_upsert'表中,并反映更新后的数据。

这个SO问题非常类似,其中一个注释建议使用“sqlalchemy表类”来执行该任务。

Update table using sqlalchemy table class

如果这是最好的(仅限),有谁能详细介绍一下我将如何在上面的具体案例中实现这一点如何实施?


Tags: to数据intestimportpandasdfdb
1条回答
网友
1楼 · 发布于 2024-06-09 08:30:47

我想最简单的方法是:

首先删除那些要“upserted”的行。这可以在循环中完成,但对于更大的数据集(5K+行)来说效率不高,所以我将DF的这一部分保存到一个临时的MySQL表中:

# assuming we have already changed values in the rows and saved those changed rows in a separate DF: `x`
x = df[mask]  # `mask` should help us to find changed rows...

# make sure `x` DF has a Primary Key column as index
x = x.set_index('a')

# dump a slice with changed rows to temporary MySQL table
x.to_sql('my_tmp', engine, if_exists='replace', index=True)

conn = engine.connect()
trans = conn.begin()

try:
    # delete those rows that we are going to "upsert"
    engine.execute('delete from test_upsert where a in (select a from my_tmp)')
    trans.commit()

    # insert changed rows
    x.to_sql('test_upsert', engine, if_exists='append', index=True)
except:
    trans.rollback()
    raise

我没有测试这段代码,所以它可能有一些小错误,但它应该给你一个想法。。。

相关问题 更多 >