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