Как обновить столбец таблицы Postgres, используя фрейм данных Pandas? - PullRequest
2 голосов
/ 07 марта 2019

Я добавляю один столбец в таблицу Postgres с более 100 столбцами через Django (новая миграция).Как я могу обновить столбец в таблице PostgreSQL данными из pandas data_frame? псевдокод для Postgres SQL ОБНОВЛЕНИЕ будет иметь вид:

UPDATE wide_table wt
SET wt.z = df.z
WHERE date = 'todays_date'

Причина, по которой я делаю это, состоит в том, что я вычисляю столбец в data_frame используя CSV, который находится в S3 (это df.z).Документы для Postgres update просты в использовании, но я не уверен, как это сделать с помощью Django, sqlalchemy, pyodbc и т.п.

Прошу прощения, если это немного запутанно.Небольшой и неполный пример:

Wide Table (столбец предварительного обновления z)

identifier    |      x       |      y      |      z       |      date       
foo           |      2       |      1      |     0.0      |      ...           
bar           |      2       |      8      |     0.0      |      ...      
baz           |      3       |      7      |     0.0      |      ...      
foo           |      2       |      8      |     0.0      |      ...      
foo           |      1       |      5      |     0.0      |      ...      
baz           |      2       |      8      |     0.0      |      ...      
bar           |      9       |      3      |     0.0      |      ...      
baz           |      2       |      3      |     0.0      |      ...      

Пример фрагмента Python

def apply_function(identifier):
    # Maps baz-> 15.0, bar-> 19.6, foo -> 10.0 for single date
    df = pd.read_csv("s3_file_path/date_file_name.csv")
    # Compute 'z' based on identifier and S3 csv
    return z

postgres_query = "Select identifier from wide_table"
df = pd.read_sql(sql=postgres_query, con=engine)
df['z'] = df.identifier.apply(apply_function)

# Python / SQL Update Logic here to update Postgres Column
???

Wide Table (post-dupate column z)

identifier    |      x       |      y      |      z        |      date 
foo           |      2       |      1      |     10.0      |      ...     
bar           |      2       |      8      |     19.6      |      ... 
baz           |      3       |      7      |     15.0      |      ... 
foo           |      2       |      8      |     10.0      |      ... 
foo           |      1       |      5      |     10.0      |      ... 
baz           |      2       |      8      |     15.0      |      ... 
bar           |      9       |      3      |     19.6      |      ... 
baz           |      2       |      3      |     15.0      |      ... 

ПРИМЕЧАНИЕ. Значения в z будут меняться ежедневно, поэтому простое создание другой таблицы для хранения этих значений z не является хорошим решением.Кроме того, я бы предпочел не удалять все данные и добавлять их обратно.

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Мне удалось самостоятельно собрать решение, в котором я сжал значения id и z, а затем выполнил общий оператор SQL UPDATE и использовал SQL UPDATE FROM VALUES.

Подготовка данных

sql_query= "SELECT id, a FROM wide_table"
df = pd.read_sql(sql=sql_query, con=engine)
df['z'] = df.a.apply(apply_function)

zipped_vals = zip(df.id, df.z)
tuple_to_str= str(tuple(zipped_vals))
entries_to_update = tuple_to_str[1:len(tuple_to_str)-1] # remove first and last paren in tuple

Решение SQL-запроса:

# Update column z by matching ID from SQL Table & Pandas DataFrame
update_sql_query = f"""UPDATE wide_table t SET z = v.z
                        FROM (VALUES {entries_to_update}) AS v (id, z)
                        WHERE t.id = v.id;"""

with engine.begin() as conn:
    conn.execute(update_sql_query)

conn.exec(sql_query)

Ответ об обновлении столбца таблицы PostgreSQL из значений

Документы по обновлению PostgreSQL

0 голосов
/ 03 июля 2019

Столкнулся с подобной проблемой, и текущее принятое решение было слишком медленным для меня. В моей таблице было более 500 тысяч строк, и мне нужно было обновить более 100 тысяч строк. После долгих исследований, проб и ошибок я нашел эффективное и правильное решение.

Идея состоит в том, чтобы использовать psycopg в качестве автора и использовать временную таблицу. df - это ваш кадр данных pandas, содержащий значения, которые вы хотите установить.

import psycopg2

conn = psycopg2.connect("dbname='db' user='user' host='localhost' password='test'")
cur = conn.cursor()

rows = zip(df.id, df.z)
cur.execute("""CREATE TEMP TABLE codelist(id INTEGER, z INTEGER) ON COMMIT DROP""")
cur.executemany("""INSERT INTO codelist (id, z) VALUES(%s, %s)""", rows)

cur.execute("""
    UPDATE table_name
    SET z = codelist.z
    FROM codelist
    WHERE codelist.id = vehicle.id;
    """)

cur.rowcount
conn.commit()
cur.close()
conn.close()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...