PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Liste Python vers tableau PostgreSQL

Notez qu'avec psycopg2 vous n'avez pas besoin de faire de traitement de chaîne pour les tableaux. Ceci est considéré comme une mauvaise pratique car il est sujet aux erreurs et peut - dans le pire des cas - conduire à l'ouverture d'attaques par injection ! Vous devez toujours utiliser des paramètres liés. Dans le code ci-dessous, je vais créer une nouvelle table avec une seule colonne avec le type TEXT[] (comme dans votre question initiale). Ensuite, je vais ajouter une nouvelle ligne et les mettre à jour toutes. Vous verrez donc à la fois un INSERT et UPDATE opération (bien que les deux soient à peu près identiques).

Il y a cependant un piège Python si vous mettez à jour avec une seule valeur :cur.execute attend l'instruction SQL comme premier argument et un itérable contenant les paramètres à lier comme second argument. Les éléments suivants ne seront pas travail :

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 raison en est que (new_values) est vu par python comme new_values (les parenthèses sont supprimées dans ce cas, elles ne sont pas considérées comme tuple). Cela entraînera l'erreur que vous fournissez 3 valeurs ('a' , 'b' et 'c' ) comme valeurs à lier, mais il n'y a qu'un seul espace réservé (%s ) dans la requête. Au lieu de cela, vous devez le spécifier comme suit (notez la virgule ajoutée à la fin) :

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

Cela fera que Python verra (new_values,) sous la forme d'un tuple (qui est un itérable) avec un élément, qui correspond aux espaces réservés de la requête. Pour une explication plus détaillée de la virgule finale, consultez la documentation officielle sur les tuples.

Alternativement, vous pouvez également écrire [new_values] au lieu de (new_values,) , mais - à mon avis - (new_values,) est plus propre car les tuples sont immuables, alors que les listes sont modifiables.

Voici le tableau avec lequel j'ai testé :

CREATE TABLE foo (
    values TEXT[]
);

Et voici le code Python qui insère et met à jour les valeurs :

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

A chaque exécution, le code insère une nouvelle ligne avec les mêmes valeurs de tableau, puis exécute une mise à jour sans WHERE clause, donc toutes les valeurs sont mises à jour. Après quelques exécutions, cela donne le résultat suivant :

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