Nota che con psycopg2
non è necessario eseguire alcuna elaborazione di stringhe per gli array. Questa è considerata una cattiva pratica in quanto è soggetta a errori e può, nel peggiore dei casi, portare ad aprire attacchi di iniezione! Dovresti sempre usare parametri vincolati. Nel codice seguente creerò una nuova tabella con una sola colonna con il tipo TEXT[]
(come nella tua domanda originale). Quindi aggiungerò una nuova riga e le aggiornerò tutte. Quindi vedrai entrambi un INSERT
e UPDATE
operazione (sebbene entrambi siano praticamente identici).
C'è un problema in Python se aggiorni con un solo valore:cur.execute
si aspetta l'istruzione SQL come primo argomento e un iterabile contenente i parametri da associare come secondo argomento. Quanto segue non lavoro:
from psycopg2 import connect
conn = connect('dbname=exhuma')
cur = conn.cursor()
stmt = 'UPDATE foo SET example_value=%s'
new_values = ['a', 'b', 'c']
cur.execute(stmt, (new_values))
conn.commit()
Il motivo è che (new_values)
è visto da Python come new_values
(le parentesi vengono eliminate in questo caso, non sono viste come tuple). Ciò comporterà l'errore di fornire 3 valori ('a'
, 'b'
e 'c'
) come valori da associare, ma è presente un solo segnaposto (%s
) nella query. Devi invece specificarlo come segue (notare la virgola aggiunta alla fine):
from psycopg2 import connect
conn = connect('dbname=exhuma')
cur = conn.cursor()
stmt = 'UPDATE foo SET example_value=%s'
new_values = ['a', 'b', 'c']
cur.execute(stmt, (new_values,))
conn.commit()
Questo farà vedere a Python (new_values,)
come una tupla (che è un iterabile) con un elemento, che corrisponde ai segnaposto della query. Per una spiegazione più dettagliata della virgola finale, vedere i documenti ufficiali sulle tuple.
In alternativa, puoi anche scrivere [new_values]
invece di (new_values,)
, ma - secondo me - (new_values,)
è più pulito poiché le tuple sono immutabili, mentre le liste sono mutabili.
Ecco la tabella con cui ho provato:
CREATE TABLE foo (
values TEXT[]
);
Ed ecco il codice Python che inserisce e aggiorna i valori:
from psycopg2 import connect
conn = connect('dbname=exhuma')
cur = conn.cursor()
cur.execute('INSERT INTO foo VALUES (%s)', (['a', 'b'], ))
print('>>> Before update')
cur.execute('SELECT * FROM foo')
for row in cur:
print(type(row[0]), repr(row[0]))
print('>>> After update')
cur.execute('UPDATE foo SET example_values = %s',
(['new', 'updated', 'values'],))
cur.execute('SELECT * FROM foo')
for row in cur:
print(type(row[0]), repr(row[0]))
cur.close()
conn.commit()
conn.close()
Ad ogni esecuzione, il codice inserirà una nuova riga con gli stessi valori dell'array, quindi eseguirà un aggiornamento senza WHERE
clausola, quindi tutti i valori vengono aggiornati. Dopo un paio di esecuzioni, questo fornisce il seguente output:
>>> Before update
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['a', 'b']")
>>> After update
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")
(<type 'list'>, "['new', 'updated', 'values']")