PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Lista Python para Matriz PostgreSQL


Observe que com psycopg2 você não precisa fazer nenhum processamento de string para arrays. Isso é considerado uma prática ruim, pois é propenso a erros e pode - na pior das hipóteses - levar à abertura de ataques de injeção! Você deve sempre usar parâmetros vinculados. No código abaixo, vou criar uma nova tabela com apenas uma coluna com o tipo TEXT[] (como na sua pergunta original). Em seguida, adicionarei uma nova linha e atualizarei todas elas. Então você verá um INSERT e UPDATE operação (embora ambos sejam praticamente idênticos).

Há uma pegadinha do Python se você atualizar com apenas um valor:cur.execute espera a instrução SQL como primeiro argumento e um iterável contendo os parâmetros a serem vinculados como segundo argumento. O seguinte não trabalhar:
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()

A razão é que (new_values) é visto por python como new_values (os parênteses são descartados neste caso, eles não são vistos como tupla). Isso resultará no erro de fornecer 3 valores ('a' , 'b' e 'c' ) como valores a serem vinculados, mas há apenas um espaço reservado (%s ) na consulta. Em vez disso, você deve especificá-lo da seguinte forma (observe a vírgula adicionada no final):
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()

Isso fará com que o Python veja (new_values,) como uma tupla (que é iterável) com um elemento, que corresponde aos espaços reservados da consulta. Para uma explicação mais detalhada da vírgula à direita, consulte os documentos oficiais sobre tuplas.

Como alternativa, você também pode escrever [new_values] em vez de (new_values,) , mas - na minha opinião - (new_values,) é mais limpo, pois as tuplas são imutáveis, enquanto as listas são mutáveis.

Segue a tabela com a qual testei:
CREATE TABLE foo (
    values TEXT[]
);

E aqui está o código Python inserindo e atualizando valores:
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()

Em cada execução, o código inserirá uma nova linha com os mesmos valores de matriz e, em seguida, executará uma atualização sem WHERE cláusula, para que todos os valores sejam atualizados. Após algumas execuções, isso fornece a seguinte saída:
>>> 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']")