如何使用熊猫数据框更新Postgres表列?

时间:2019-03-07 20:35:02

标签: python pandas postgresql dataframe

我正在通过Django向Postgres表中添加100列以上的单列(新迁移)。如何使用pandas data_frame中的数据更新PostgreSQL表中的列? Postgres SQL UPDATE伪代码为:

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

这样做的原因是,我正在使用data_frame(即S3)中的CSV计算df.z中的一列。 Postgres update的文档易于使用,但是我不确定如何通过Django,sqlalchemy,pyodbc等执行此操作。

很抱歉,这有点令人费解。一个不完整的小例子是:

宽表(更新前列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
???

宽表(更新后的列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 个答案:

答案 0 :(得分:0)

我设法自己拼凑出一个解决方案,在其中压缩idz值,然后执行通用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)

Answer关于从值更新PostgreSQL表列

PostgreSQL update docs

答案 1 :(得分:0)

遇到了类似的问题,当前接受的解决方案对我来说太慢了。我的表有500k +行,我需要更新100k +行。经过长时间的研究和反复试验,我得出了一个有效而正确的解决方案。

该想法是使用psycopg作为编写器并使用临时表。 <label>Agent ID<span style="color: red; font-size: 18px; font-weight: bold;">*</span></label> <input type="text" minlength="16" maxlength="16" id="txt_agent_nik" name="txt_agent_nik" class="form-control required"> <label>Principal<span style="color: red; font-size: 18px; font-weight: bold;">*</span></label> <input type="text" id="txt_agent_nik" name="txt_agent_nik" class="form-control required"> <a href="#" id="btnGenCobrokedetails"><span class="icon-arrow-right-3">Check Agent</span></a>是您的熊猫数据框,其中包含您要设置的值。

df