Pandas обновить sql

Есть ли способ сделать обновление SQL - откуда из фреймворка без итерации через каждую строку? У меня есть база данных postgresql и для обновления таблицы в db из фрейма данных я бы использовал psycopg2 и сделал что-то вроде:

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()

Но с другой стороны, если im либо читает таблицу из sql, либо записывает целую фреймворк данных в sql (без обновления-где), тогда я бы просто использовал pandas и sqlalchemy. Что-то вроде:

engine = create_engine('postgresql+psycopg2://user:[email protected]')
df.to_sql('table', engine, if_exists='append')

Хорошо, что у меня есть "однострочный", используя to_sql. Не похоже ли что-то подобное обновлению - от pandas до postgresql? Или это единственный способ сделать это, повторяя каждую строку, как я сделал выше. Не повторяется ли в каждой строке неэффективный способ сделать это?

Ответы

Ответ 1

Рассмотрим временную таблицу, которая будет точной копией вашей итоговой таблицы, очищенной при каждом запуске:

engine = create_engine('postgresql+psycopg2://user:[email protected]')
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)

Ответ 2

Похоже, что вы используете некоторые внешние данные, хранящиеся в df, для условий обновления таблицы базы данных. Если возможно, почему бы просто не сделать однострочное обновление sql?

Если вы работаете с маленькой базой данных (где загрузка всех данных в объект фреймворка python не собирается вас убивать), вы можете определенно условно обновлять dataframe после загрузки с помощью read_sql. Затем вы можете использовать ключевое слово arg if_exists="replace", чтобы заменить таблицу DB новой обновленной таблицей.

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 - мощный инструмент, в котором ограниченная поддержка SQL была сначала небольшой функцией. С течением времени люди пытаются использовать pandas в качестве своего единственного программного обеспечения для интерфейса базы данных. Я не думаю, что pandas всегда предназначался для взаимодействия с базой данных, но многие люди постоянно работают над новыми функциями. См.: https://github.com/pandas-dev/pandas/issues

Ответ 3

До сих пор я не видел случая, когда соединитель pandas sql можно использовать любым масштабируемым способом для обновления данных базы данных. Казалось бы, неплохо было построить один, но действительно, для оперативной работы он просто не масштабируется.

То, что я бы рекомендовал, состоит в том, чтобы сбрасывать весь ваш фреймворк в формате CSV с помощью

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

Затем загрузите CSV в базу данных, используя COPY для PostgreSQL или LOAD DATA INFILE для MySQL.

Если вы не вносите другие изменения в рассматриваемую таблицу, пока данные обрабатываются с помощью pandas, вы можете просто загрузить в таблицу.

Если есть проблемы concurrency, вам придется загрузить данные в промежуточную таблицу, которую вы затем используете для обновления вашей основной таблицы.

В последнем случае ваша основная таблица должна иметь дату-время, которое сообщает вам, когда последняя модификация была таким образом, чтобы вы могли определить, являются ли ваши изменения pandas последними или если изменения базы данных должны оставаться.

Ответ 4

Мне было интересно, почему бы вам не обновить df сначала на основе вашего уравнения, а затем сохранить df в базе данных, вы можете использовать if_exists = 'replace', чтобы хранить в той же таблице.