sql >> Base de Datos >  >> RDS >> PostgreSQL

Lista de Python a matriz PostgreSQL

Tenga en cuenta que con psycopg2 no necesita hacer ningún procesamiento de cadenas para matrices. Esto se considera una mala práctica, ya que es propenso a errores y puede, en el peor de los casos, conducir a la apertura de ataques de inyección. Siempre debe usar parámetros enlazados. En el siguiente código, crearé una nueva tabla con una sola columna con el tipo TEXT[] (como en su pregunta original). Luego agregaré una nueva fila y las actualizaré todas. Entonces verás un INSERT y UPDATE funcionamiento (aunque ambos son prácticamente idénticos).

Sin embargo, hay un error de Python si actualiza con un solo valor:cur.execute espera la sentencia SQL como primer argumento y un iterable que contiene los parámetros que se vincularán como segundo argumento. Lo siguiente no trabajo:

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()

La razón es que (new_values) es visto por python como new_values (los paréntesis se eliminan en este caso, no se ven como tupla). Esto dará como resultado el error de proporcionar 3 valores ('a' , 'b' y 'c' ) como valores a vincular, pero solo hay un marcador de posición (%s ) en la consulta. En su lugar, debe especificarlo de la siguiente manera (observe la coma agregada al 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()

Esto hará que Python vea (new_values,) como una tupla (que es iterable) con un elemento, que coincide con los marcadores de posición de la consulta. Para obtener una explicación más detallada de la coma final, consulte los documentos oficiales sobre tuplas.

Alternativamente, también podría escribir [new_values] en lugar de (new_values,) , pero, en mi opinión, (new_values,) es más limpio ya que las tuplas son inmutables, mientras que las listas son mutables.

Aquí está la tabla con la que probé:

CREATE TABLE foo (
    values TEXT[]
);

Y aquí está el código Python tanto para insertar como para actualizar 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()

En cada ejecución, el código insertará una nueva fila con los mismos valores de matriz, luego ejecutará una actualización sin WHERE cláusula, por lo que todos los valores se actualizan. Después de un par de ejecuciones, esto da el siguiente resultado:

>>> 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']")