Python / postgres / psycopg2: ID der gerade eingefügten Zeile abrufen

98

Ich benutze Python und psycopg2, um eine Schnittstelle zu Postgres herzustellen.

Wenn ich eine Zeile einfüge ...

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

... wie bekomme ich die ID der Zeile, die ich gerade eingefügt habe? Versuch:

hundred = cursor.fetchall() 

Gibt bei Verwendung von Folgendes einen Fehler zurück 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)

kehrt einfach zurück None.

UPDATE: So auch currval(obwohl die Verwendung dieses Befehls direkt in postgres funktioniert):

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

Kann mir jemand raten?

Vielen Dank!

AP257
quelle

Antworten:

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

Und bitte erstellen Sie keine SQL-Zeichenfolgen, die Werte enthalten, manuell. Sie können (und sollten!) Werte separat übergeben, sodass ein Escape-Vorgang und eine SQL-Injection nicht erforderlich sind:

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]

Weitere Informationen finden Sie in den Psycopg-Dokumenten: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries

DiebMaster
quelle
11
Zur Verdeutlichung sollte das idin RETURNING idder Feldname des Serien- / Primärschlüsselfelds sein.
Joshden
9
Cursor-Fetchone gibt mir "keine Ergebnisse zum Abrufen".
Leonid
@Leonid hast du das herausgefunden?
Alison S
4
@AlisonS @Leonid Ich hatte den gleichen Fehler, aber das Hinzufügen RETURNING idam Ende der INSERTAbfrage hat ihn für mich behoben.
Banjer
Vielleicht nur eine kleine Notiz, aber wichtiger Punkt für alle zu erwähnen: Stellen Sie sicher , dass Sie nur die Cursor mit .execute () und nicht um einen Cursor .mogrify () vor der execute () Befehl, sonst (wie in meinem Fall) cursor.fetchone () wird keine Ergebnisse haben! Wenn Sie vor diesem Befehl nur den Cursor .execute () ohne "irgendetwas" verwenden, erhalten Sie eine ID.
TheHeroOfTime
14

Ich bin hier gelandet, weil ich ein ähnliches Problem hatte, aber wir verwenden Postgres-XC, das die RETURNING ID-Klausel noch nicht unterstützt. In diesem Fall können Sie verwenden:

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

Nur für den Fall, dass es für irgendjemanden nützlich war!

Jamie Brown
quelle
4
Denken Sie daran: Wenn Sie dies in zwei solchen Anweisungen tun, besteht ein (sehr geringes) Risiko für die Rennbedingungen, wenn etwas direkt nach Ihnen eine Zeile in die Datenbank einfügt, aber bevor Ihr Befehl lastval () den aktuellen Wert der Sequenz zurückgibt.
Dave Thomas