web-dev-qa-db-fra.com

Mise à jour des pandas sql

Existe-t-il un moyen de faire une mise à jour SQL-où depuis un cadre de données sans effectuer une itération sur chaque ligne? J'ai une base de données postgresql et pour mettre à jour une table dans la base de données à partir d'un cadre de données, je voudrais utiliser psycopg2 et faire quelque chose comme:

con = psycopg2.connect(database='mydb', user='abc', password='xyz')
cur = con.cursor()

for index, row in df.iterrows():
    sql = 'update table set column = %s where column = %s'
    cur.execute(sql, (row['whatver'], row['something']))
con.commit()

Mais d’autre part, si je lis une table à partir de SQL ou écrit tout un cadre de données en SQL (sans mise à jour), je voudrais simplement utiliser pandas et sqlalchemy. Quelque chose comme:

engine = create_engine('postgresql+psycopg2://user:pswd@mydb')
df.to_sql('table', engine, if_exists='append')

C'est génial d'avoir juste un 'one-liner' utilisant to_sql. N'y a-t-il pas quelque chose de similaire à faire une mise à jour, où de pandas à postgresql? Ou est le seul moyen de le faire en parcourant chaque ligne comme je l’ai fait plus haut. Parcourir chaque ligne n’est-il pas un moyen inefficace de le faire?

23
darkpool

Considérons une table temporaire qui serait la réplique exacte de votre table finale, nettoyée à chaque exécution:

engine = create_engine('postgresql+psycopg2://user:pswd@mydb')
df.to_sql('temp_table', engine, if_exists='replace')

sql = """
    UPDATE final_table AS f
    SET col1 = t.col1
    FROM temp_table AS t
    WHERE f.id = t.id
"""

with engine.begin() as conn:     # TRANSACTION
    conn.execute(sql)
23
Parfait

Il semble que vous utilisiez des données externes stockées dans df pour les conditions de mise à jour de votre table de base de données. Si c'est possible, pourquoi ne pas simplement mettre à jour une ligne SQL?

Si vous travaillez avec une petite base de données (où le chargement de l'intégralité des données dans l'objet python dataframe ne va pas vous tuer), vous pouvez mettre définitivement à jour le frame de données de manière conditionnelle après l'avoir chargé avec read_sql. Ensuite, vous pouvez utiliser un mot clé arg if_exists="replace" pour remplacer la table de base de données par la nouvelle table mise à jour.

df = pandas.read_sql("select * from your_table;", engine)

#update information (update your_table set column = "new value" where column = "old value")
#still may need to iterate for many old value/new value pairs
df[df['column'] == "old value", "column"] = "new value"

#send data back to sql
df.to_sql("your_table", engine, if_exists="replace")

Pandas est un outil puissant, où la prise en charge limitée de SQL n’était au départ qu’une petite fonctionnalité. Au fil du temps, les gens essaient d'utiliser des pandas comme seul logiciel d'interface de base de données. Je ne pense pas que les pandas aient jamais été conçus pour être une solution finale pour l'interaction de base de données, mais beaucoup de personnes travaillent constamment sur de nouvelles fonctionnalités. Voir: https://github.com/pandas-dev/pandas/issues

6
jeffery_the_wind

Jusqu'à présent, je n'ai pas vu de cas où le connecteur pandas sql puisse être utilisé de manière évolutive pour mettre à jour données de base de données. C’est peut-être une bonne idée d’en construire un, mais en réalité, le travail opérationnel n’a pas d’échelle.

Ce que je recommanderais est de vider l'intégralité de votre image de données en tant que CSV en utilisant

df.to_csv('filename.csv', encoding='utf-8')

Puis chargez le fichier CSV dans la base de données à l’aide de COPY pour PostgreSQL ou LOAD DATA INFILE pour MySQL.

Si vous n'apportez pas d'autres modifications à la table en question pendant que les données sont manipulées par des pandas, vous pouvez simplement les charger dans la table.

En cas de problèmes de simultanéité, vous devrez charger les données dans une table intermédiaire que vous utiliserez ensuite pour mettre à jour votre table primaire.

Dans le dernier cas, votre table principale doit avoir une date/heure qui vous indique la dernière modification. Vous pouvez ainsi déterminer si vos modifications de pandas sont les plus récentes ou si les modifications de la base de données doivent rester.

1
firelynx

Je me demandais pourquoi ne pas mettre à jour le fichier df d’abord en fonction de votre équation, puis le stocker dans la base de données; vous pouvez utiliser if_exists = 'replace' pour stocker sur la même table.

0
nabaz

Si vous devez mettre à jour un panda en fonction de plusieurs conditions pour simuler le code SQL:

UPDATE table WHERE A > 7 AND B > 69

Vous pouvez simplement utiliser .loc

>>> df
      A   B    C
0     2  40  800
1     1  90  600
2     6  80  700
3  1998  70   55
4     1  90  300
5     7  80  700
6     4  20  300
7  1998  20    2
8     7  10  100
9  1998  60    2

>>> df.loc[(df['A'] > 7) & (df['B'] > 69) , 'C'] = 75

Ceci établira 'C' = 75 où 'A'> 7 et 'B'> 69

0
HoosierCoder