Zauważ, że z psycopg2
nie musisz wykonywać żadnego przetwarzania ciągów dla tablic. Jest to uważane za złą praktykę, ponieważ jest podatne na błędy i może – w najgorszym przypadku – prowadzić do ataków iniekcji! Zawsze należy używać powiązanych parametrów. W poniższym kodzie utworzę nową tabelę z tylko jedną kolumną typu TEXT[]
(jak w pierwotnym pytaniu). Następnie dodam nowy wiersz i zaktualizuję je wszystkie. Zobaczysz więc zarówno INSERT
i UPDATE
operacja (chociaż oba są prawie identyczne).
Istnieje jednak jeden problem w Pythonie, jeśli aktualizujesz tylko jedną wartość:cur.execute
oczekuje instrukcji SQL jako pierwszego argumentu i iterowalnego zawierające parametry do powiązania jako drugi argument. Poniższe nie praca:
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()
Powodem jest to, że (new_values)
jest postrzegany przez pythona jako new_values
(w tym przypadku nawiasy są odrzucane, nie są postrzegane jako krotka). Spowoduje to błąd, że podajesz 3 wartości ('a'
, 'b'
i 'c'
) jako wartości do powiązania, ale jest tylko jeden symbol zastępczy (%s
) w zapytaniu. Zamiast tego musisz określić to w następujący sposób (zwróć uwagę na dodany przecinek na końcu):
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()
Spowoduje to, że Python zobaczy (new_values,)
jako krotka (która jest iterowalna) z jednym elementem, który pasuje do symboli zastępczych zapytania. Bardziej szczegółowe wyjaśnienie końcowego przecinka znajduje się w oficjalnych dokumentach dotyczących krotek.
Alternatywnie możesz również napisać [new_values]
zamiast (new_values,)
, ale - moim zdaniem - (new_values,)
jest czystsze, ponieważ krotki są niezmienne, podczas gdy listy są zmienne.
Oto tabela, z którą testowałem:
CREATE TABLE foo (
values TEXT[]
);
A oto kod Pythona zarówno wstawiający, jak i aktualizujący wartości:
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()
Przy każdym wykonaniu kod wstawi nowy wiersz z tymi samymi wartościami tablicy, a następnie wykona aktualizację bez WHERE
klauzula, więc wszystkie wartości są aktualizowane. Po kilku wykonaniach daje to następujący wynik:
>>> 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']")