Python / postgres / psycopg2: pobieranie ID właśnie wstawionego wiersza

105

Używam Pythona i psycopg2 do połączenia z postgres.

Kiedy wstawiam wiersz ...

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

... jak uzyskać identyfikator właśnie wstawionego wiersza? Próbować:

hundred = cursor.fetchall() 

zwraca błąd podczas używania 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)

po prostu wraca None.

AKTUALIZACJA: Tak robi currval(nawet jeśli użycie tego polecenia bezpośrednio w postgres działa):

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

Czy ktoś może doradzić?

dzięki!

AP257
źródło

Odpowiedzi:

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

I proszę nie tworzyć ręcznie łańcuchów SQL zawierających wartości. Możesz (i powinieneś!) Przekazywać wartości osobno, dzięki czemu nie ma potrzeby ucieczki i iniekcji SQL:

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]

Zobacz dokumentację psycopg po więcej szczegółów: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries

ThiefMaster
źródło
13
Dla wyjaśnienia, idin RETURNING idpowinno być nazwą pola pola klucza seryjnego / podstawowego.
joshden,
11
kursor fetchone daje mi „brak wyników do pobrania”.
Leonid
@Leonid, czy odkryłeś to?
Alison S
5
@AlisonS @Leonid Miałem ten sam błąd, ale dodanie RETURNING idna końcu INSERTzapytania naprawiło go.
Banjer,
Może tylko mała uwaga, ale ważna uwaga dla wszystkich: Upewnij się, że używasz tylko kursora .execute (), a nie kursora .mogrify () przed poleceniem execute () , w przeciwnym razie (jak w moim przypadku) kursor.fetchone () nie przyniesie żadnych wyników! Używając tylko kursora .execute () bez "niczego" przed tym poleceniem, otrzymasz identyfikator.
TheHeroOfTime
14

Skończyło się tutaj, ponieważ miałem podobny problem, ale używamy Postgres-XC, który jeszcze nie obsługuje klauzuli RETURNING ID. W takim przypadku możesz użyć:

kursor.execute ('WSTAW DO ........')
kursor.execute ('SELECT LASTVAL ()')
lastid = kursor.fetchone () ['lastval']

Na wszelki wypadek, gdyby było to przydatne dla każdego!

Jamie Brown
źródło
4
Pamiętaj tylko - zrobienie tego w dwóch takich instrukcjach powoduje (bardzo małe) ryzyko wystąpienia warunków wyścigu, jeśli coś wstawia wiersz do bazy danych bezpośrednio po tobie, ale zanim polecenie lastval () zwraca bieżącą wartość sekwencji.
Dave Thomas