我有一个表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'))
没有返回任何内容。这有什么问题?顺便说一句,我也尝试在一个事务中显式运行这些查询,并得到完全相同的结果。
答案 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
[ 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]