Имайте предвид, че с psycopg2
не е необходимо да извършвате обработка на низове за масиви. Това се счита за лоша практика, тъй като е податлива на грешки и може – в най-лошия случай – да доведе до отваряне на атаки с инжектиране! Винаги трябва да използвате свързани параметри. В кода по-долу ще създам нова таблица само с една колона с тип TEXT[]
(както в оригиналния ви въпрос). След това ще добавя нов ред и ще актуализирам всички. Така че ще видите и двете INSERT
и UPDATE
операция (въпреки че и двете са почти идентични).
Въпреки това има един проблем с Python, ако актуализирате само с една стойност:cur.execute
очаква SQL израза като първи аргумент и итерируем съдържащ параметрите, които трябва да бъдат обвързани като втори аргумент. Следното не работа:
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()
Причината е, че (new_values)
се вижда от python като new_values
(в този случай скобите се изпускат, не се виждат като кортежи). Това ще доведе до грешка, че предоставяте 3 стойности ('a'
, 'b'
и 'c'
) като стойности, които трябва да бъдат обвързани, но има само един заместител (%s
) в заявката. Вместо това трябва да го посочите по следния начин (забележете добавената запетая в края):
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()
Това ще накара Python да вижда (new_values,)
като кортеж (който е итерируем) с един елемент, който съвпада с заместващите места на заявката. За по-подробно обяснение на крайната запетая вижте официалните документи за кортежи.
Като алтернатива можете също да напишете [new_values]
вместо (new_values,)
, но - според мен - (new_values,)
е по-чист, тъй като кортежите са неизменни, докато списъците са променливи.
Ето таблицата, с която тествах:
CREATE TABLE foo (
values TEXT[]
);
И ето Python код, който вмъква и актуализира стойности:
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()
При всяко изпълнение кодът ще вмъкне нов ред със същите стойности на масива, след което ще изпълни актуализация без WHERE
клауза, така че всички стойности се актуализират. След няколко екзекуции аз това дава следния изход:
>>> 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']")