Python / postgres / psycopg2: obtention de l'ID de la ligne qui vient d'être insérée

99

J'utilise Python et psycopg2 pour m'interfacer avec postgres.

Quand j'insère une ligne ...

sql_string = "INSERT INTO hundred (name,name_slug,status) VALUES ("
sql_string += hundred_name + ", '" + hundred_slug + "', " + status + ");"
cursor.execute(sql_string)

... comment obtenir l'ID de la ligne que je viens d'insérer? En essayant:

hundred = cursor.fetchall() 

renvoie une erreur, lors de l'utilisation RETURNING id:

sql_string = "INSERT INTO domes_hundred (name,name_slug,status) VALUES ("
sql_string += hundred_name + ", '" + hundred_slug + "', " + status + ") RETURNING id;"
hundred = cursor.execute(sql_string)

retourne simplement None.

UPDATE: Il en va de currvalmême (même si l'utilisation de cette commande directement dans postgres fonctionne):

sql_string = "SELECT currval(pg_get_serial_sequence('hundred', 'id'));"
hundred_id = cursor.execute(sql_string)

Quelqu'un peut-il conseiller?

Merci!

AP257
la source

Réponses:

206
cursor.execute("INSERT INTO .... RETURNING id")
id_of_new_row = cursor.fetchone()[0]

Et veuillez ne pas créer manuellement des chaînes SQL contenant des valeurs. Vous pouvez (et devriez!) Transmettre les valeurs séparément, ce qui rend inutile l'échappement et l'injection SQL impossible:

sql_string = "INSERT INTO domes_hundred (name,name_slug,status) VALUES (%s,%s,%s) RETURNING id;"
cursor.execute(sql_string, (hundred_name, hundred_slug, status))
hundred = cursor.fetchone()[0]

Consultez la documentation psycopg pour plus de détails: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries

ThiefMaster
la source
12
Juste pour clarifier, le idin RETURNING iddoit être le nom de champ du champ de clé série / primaire.
joshden
9
le curseur fetchone ne me donne "aucun résultat à récupérer".
Leonid
@Leonid avez-vous compris cela?
Alison S
4
@AlisonS @Leonid J'ai eu la même erreur, mais l'ajout RETURNING idà la fin de la INSERTrequête l'a corrigée pour moi.
Banjer
Peut-être juste une petite note, mais un point important à mentionner pour tout le monde: assurez-vous que vous n'utilisez que le curseur .execute () et non un curseur .mogrify () avant la commande execute () , sinon (comme dans mon cas) cursor.fetchone () n'aura aucun résultat! En utilisant uniquement le curseur .execute () sans "rien" avant cette commande, vous recevrez un identifiant.
TheHeroOfTime
14

Je me suis retrouvé ici parce que j'avais un problème similaire, mais nous utilisons Postgres-XC, qui ne prend pas encore en charge la clause RETURNING ID. Dans ce cas, vous pouvez utiliser:

curseur.execute ('INSERT INTO ........')
curseur.execute ('SELECT LASTVAL ()')
lastid = cursor.fetchone () ['lastval']

Juste au cas où cela serait utile à n'importe qui!

Jamie Brown
la source
4
Rappelez-vous simplement que le faire dans deux instructions comme celle-ci présente un (très petit) risque de conditions de concurrence, si quelque chose insère une ligne dans la base de données directement après vous, mais avant que votre commande lastval () ne renvoie la valeur actuelle de la séquence.
Dave Thomas