Python / postgres / psycopg2: obtendo o ID da linha recém-inserida

99

Estou usando Python e psycopg2 para fazer interface com o postgres.

Quando eu insiro uma linha ...

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

... como obtenho o ID da linha que acabei de inserir? Tentando:

hundred = cursor.fetchall() 

retorna um erro, ao usar 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)

simplesmente retorna None.

ATUALIZAÇÃO: O mesmo acontece currval(embora usando este comando diretamente no postgres funcione):

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

Alguém pode aconselhar?

obrigado!

AP257
fonte

Respostas:

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

E, por favor, não construa strings SQL contendo valores manualmente. Você pode (e deve!) Passar valores separadamente, tornando desnecessário o escape e a injeção de SQL impossível:

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]

Consulte a documentação do psycopg para obter mais detalhes: http://initd.org/psycopg/docs/usage.html#passing-parameters-to-sql-queries

ThiefMaster
fonte
12
Só para esclarecer, o idin RETURNING iddeve ser o nome do campo do campo da chave serial / primária.
joshden
9
cursor fetchone me dá "nenhum resultado para buscar".
Leonid
@Leonid você descobriu isso?
Alison S
4
@AlisonS @Leonid Eu tive o mesmo erro, mas adicionar RETURNING idno final da INSERTconsulta corrigiu para mim.
Banjer
Talvez apenas uma pequena observação, mas um ponto importante a ser mencionado para todos: certifique-se de usar apenas cursor .execute () e não um cursor .mogrify () antes do comando execute () , caso contrário (como no meu caso) cursor.fetchone () não terá nenhum resultado! Usando apenas cursor .execute () sem "nada" antes desse comando, você receberá um id.
TheHeroOfTime
14

Acabei aqui porque tive um problema semelhante, mas estamos usando Postgres-XC, que ainda não suporta a cláusula RETURNING ID. Nesse caso, você pode usar:

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

Para o caso de ser útil para alguém!

Jamie Brown
fonte
4
Apenas lembre-se - fazer isso em duas instruções como essa corre um risco (muito pequeno) de condições de corrida, se algo inserir uma linha no banco de dados diretamente depois de você, mas antes de seu comando lastval () retornar o valor atual da sequência.
Dave Thomas