无法使用Python在PostgreSQL中获取最后一个插入的id

时间:2015-12-12 16:57:19

标签: python postgresql

我有一个表test_table,其字段id会自动递增。现在我想要的是在运行INSERT语句后立即获取最后一个插入的ID。此时我的所有尝试都会导致None(顺便说一句,我在MySQL中得到了相同的行为,只有在SQLite中一切正常)。这是一些重现这种意外行为的代码:

>>> import psycopg2
>>> cnx = psycopg2.connect(host="127.0.0.1", dbname="reestr", user="postgres", password="postgres")
>>> cur = cnx.cursor()
>>> cur.execute("INSERT INTO test_table (field_1) VALUES ('hello')")
>>> cur.execute("INSERT INTO test_table (field_1) VALUES ('hello')")
>>> cur.execute("SELECT CURRVAL(pg_get_serial_sequence('test_table','id'))")
>>> res = cur.fetchone()
>>> res
(None,)
>>> cur.execute("SELECT id, field_1 FROM test_table")
>>> res = cur.fetchall()
>>> res
[(1, 'hello'), (2, 'hello')]

我们清楚地看到,id列自动增量因为某些疯狂的原因SELECT CURRVAL(pg_get_serial_sequence('test_table','id'))没有返回任何内容。这有什么问题?顺便说一句,我也尝试在一个事务中显式运行这些查询,并得到完全相同的结果。

1 个答案:

答案 0 :(得分:6)

因为PostgreSQL doc说:

  

pg_get_serial_sequence(table_name,column_name)|文字|获取序列或bigserial 列使用

的序列的名称

(强调我的)因为你的专栏没有明确地声明为SERIAL或BIGSERIAL,pg_get_serial_sequence什么都不返回。如果您想使用pg_get_serial_sequence,则必须声明:

CREATE TABLE test_table (id SERIAL, field_1 VARCHAR(128))

无论如何,生成的密钥是PostgreSQL中的常见问题。我在Java中遇到过它,但它在Python中应该是相同的。

PostgreSQL具有RETURNING的特定扩展名,而不是从游标中访问最后生成的键的常用习惯用法。从INSERT

的PostreSQL文档中提取
[ WITH [ RECURSIVE ] with_query [, ...] ]
INSERT INTO table [ ( column [, ...] ) ]
    { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query }
    [ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
  

...可选的RETURNING子句使INSERT根据实际插入的每一行计算和返回值。这主要用于获取默认值提供的值,例如序列号... RETURNING列表的语法与SELECT输出列表的语法相同。

所以我的建议是坚持你当前的声明,但是将你的插入代码更改为:

>>> cur.execute("INSERT INTO test_table (field_1) VALUES ('hello') RETURNING id")
>>> res = cur.fetchone()
>>> last_inserted_id = res[0]