3

In an existing PostgreSQL table, I would like to UPDATE several existing columns with values from a dictionary lookup (see dict below). Somewhat like described in this nice blog post. However, I can't figure out how to do that with a Python dictionary. Here comes the terrible pseudo-code:

d = {10:'chair', 11:'table', 12:'lamp', 
    20:'english ivy', 21:'peace lily', 22:'spider plant'}

curs.execute("""
    UPDATE my_table t
    SET furniture = %(t.furniture)s,
    SET plant = %(t.plant)s""",
    d)

The original table would look somewhat like this:

gid | furniture | plant
-----------------------
 0  |    10     |  21
 1  |    11     |  20
 ...

After the operation it should look like this:

gid | furniture |    plant
-----------------------------
 0  |   chair   | peace lily
 1  |   table   | english ivy
 ...

Is this possible or will I have to loop through the table?

3
  • stackoverflow.com/questions/7019831/… Commented May 11, 2015 at 8:01
  • do you know about SQLAlchemy? Commented May 11, 2015 at 8:01
  • @Ashalynd Thanks! I'm note sure how the linked question could solve my problem - sorry. I played with SQLAlchemy's ORM. But apparently I don't know it well enough. Does it have a tool for that? Commented May 11, 2015 at 8:11

2 Answers 2

9

try this:

rows = (
    {'gid': 10, 'furniture': 10, 'plant': 10},
    {'gid': 20, 'furniture': 20, 'plant': 20}
)
cur.executemany(
    '''
        UPDATE myTable 
        SET
            furniture = %(furniture)s,
            plant = %(plant)s
        WHERE
            gid = %(gid)s
    ''',
    rows
)
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks - but it seems like I wasn't clear in my question. I will edit it now... I am very sorry about that.
If type of myTable.furniture text-compatible (text, character varying, etc) - no problems. Just change value of rows (rows[i].furniture = 'chair'). Otherwise change column type first (ALTER TABLE myTable ALTER COLUMN furniture TYPE text;)
Obviously I am not getting something here. Are you saying I should prepare a list of dictionaries beforehand in order to update the table basically row-by-row? But my database is huge, in random order, and the replacement dict has many entries. I would like to update in-place - if possible.
executemany is faster than execute in loop, but if you need maximum speed read this stackoverflow.com/questions/8910494/…
So it is not possible to update inplace with a dict? After giving some more thought, it makes sense though: It would require
|
0

The approach of catver works. However, I found that creating a temporary table proved to be more efficient.

import psycopg2
from psycopg2.extensions import AsIs

rows = zip(d.keys(), d.values())
curs.execute("""
    CREATE TEMP TABLE codelist(DKEY INTEGER, DVALUE TEXT) 
    ON COMMIT DROP""")

curs.executemany("""
  INSERT INTO codelist (DKEY, DVALUE)
  VALUES(%s, %s)""",
  rows)

for i in [(AsIs('furniture'), AsIs('furniture')), (AsIs('plant'), AsIs('plant'))]:
    curs.execute("""
        UPDATE my_table
        SET %s = codelist.DVALUE
        FROM codelist
        WHERE codelist.DKEY = my_table.%s;
        """, i)

NB: This example may not quite work because I am replacing INTEGER with TEXT values. This may throw the error ERROR: operator does not exist: integer = character varying. In that case, this answer might help.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.