Bemærk, at med psycopg2
du behøver ikke at lave nogen strengbehandling for arrays. Dette anses for at være lige så dårlig praksis, da det er fejlbehæftet og kan - i værste fald - føre til at der åbnes op for injektionsangreb! Du bør altid bruge bundne parametre. I koden nedenfor vil jeg oprette en ny tabel med kun én kolonne med typen TEXT[]
(som i dit oprindelige spørgsmål). Så vil jeg tilføje en ny række og opdatere dem alle. Så du vil både se en INSERT
og UPDATE
operation (selvom begge er stort set identiske).
Der er dog en Python-gotcha, hvis du kun opdaterer med én værdi:cur.execute
forventer SQL-sætningen som første argument og en iterbar indeholdende parametrene, der skal bindes som andet argument. Følgende vil ikke arbejde:
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()
Årsagen er, at (new_values)
ses af python som new_values
(forældrene er droppet i dette tilfælde, de ses ikke som tupel). Dette vil resultere i den fejl, at du angiver 3 værdier ('a'
, 'b'
og 'c'
) som værdier, der skal bindes, men der er kun én pladsholder (%s
) i forespørgslen. I stedet skal du angive det som følger (bemærk det tilføjede komma i slutningen):
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()
Dette vil få Python til at se (new_values,)
som en tuple (som er en iterabel) med ét element, som matcher forespørgslens pladsholdere. For en mere detaljeret forklaring af det efterfølgende komma, se de officielle dokumenter om tupler.
Alternativt kan du også skrive [new_values]
i stedet for (new_values,)
, men - efter min mening - (new_values,)
er renere, da tupler er uforanderlige, hvorimod lister er foranderlige.
Her er tabellen, som jeg testede med:
CREATE TABLE foo (
values TEXT[]
);
Og her er Python-kode, der både indsætter og opdaterer værdier:
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()
Ved hver udførelse vil koden indsætte en ny række med de samme matrixværdier og derefter udføre en opdatering uden WHERE
klausul, så alle værdier er opdateret. Efter et par henrettelser giver I dette følgende 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']")