Všimněte si, že s psycopg2
pro pole nemusíte provádět žádné zpracování řetězců. To je považováno za špatný postup, protože je náchylný k chybám a může - v nejhorším případě - vést k otevření injekčních útoků! Vždy byste měli používat vázané parametry. V níže uvedeném kódu vytvořím novou tabulku pouze s jedním sloupcem typu TEXT[]
(jako ve vaší původní otázce). Poté přidám nový řádek a aktualizuji všechny. Takže uvidíte jak INSERT
a UPDATE
operace (ačkoli obě jsou téměř totožné).
Existuje však jeden Python gotcha, pokud aktualizujete pouze jednu hodnotu:cur.execute
očekává příkaz SQL jako první argument a iterovatelný obsahující parametry, které mají být svázány jako druhý argument. Následující nebude práce:
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()
Důvodem je, že (new_values)
je pythonem viděn jako new_values
(závorky jsou v tomto případě vynechány, nejsou vnímány jako n-tice). To bude mít za následek chybu, že zadáte 3 hodnoty ('a'
, 'b'
a 'c'
) jako hodnoty, které mají být svázány, ale existuje pouze jeden zástupný symbol (%s
) v dotazu. Místo toho jej musíte zadat následovně (všimněte si přidané čárky na konci):
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()
To způsobí, že Python uvidí (new_values,)
jako n-tici (která je iterovatelná) s jedním prvkem, který odpovídá zástupným symbolům dotazu. Podrobnější vysvětlení koncové čárky naleznete v oficiálních dokumentech o n-ticích.
Případně můžete také napsat [new_values]
místo (new_values,)
, ale - podle mého názoru - (new_values,)
je čistší, protože n-tice jsou neměnné, zatímco seznamy jsou proměnlivé.
Zde je tabulka, se kterou jsem testoval:
CREATE TABLE foo (
values TEXT[]
);
A zde je kód Pythonu pro vkládání a aktualizaci hodnot:
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()
Při každém spuštění kód vloží nový řádek se stejnými hodnotami pole a poté provede aktualizaci bez WHERE
klauzule, takže všechny hodnoty jsou aktualizovány. Po několika provedeních to dává následující výstup:
>>> 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']")