【问题标题】:Getting the id of the last record inserted for Postgresql SERIAL KEY with PythonSqlAlchemy:获取插入的最后一条记录的 id
【发布时间】:2012-01-25 06:09:05
【问题描述】:

我正在使用没有 ORM 的 SQLAlchemy,即使用手工制作的 SQL 语句直接与后端数据库交互。在这种情况下,我使用 PG 作为我的后端数据库(psycopg2 作为数据库驱动程序) - 我不知道这是否会影响答案。

我有这样的陈述(为简洁起见,假设 conn 是与数据库的有效连接):

conn.execute("INSERT INTO user (name, country_id) VALUES ('Homer', 123)")

还假设用户表由列(id [SERIAL PRIMARY KEY]、name、country_id)组成

如何获取新用户的 id(最好不要再次访问数据库?)

【问题讨论】:

  • 这和 SQLAlchemy 有什么关系?
  • 对于mysqlsqlalchemy,使用result.lastrowid。我知道这个问题是针对postgresql 的,谷歌没有,可能是因为标题。

标签: python postgresql sqlalchemy psycopg2


【解决方案1】:

您也许可以像这样使用INSERT statementRETURNING 子句:

result = conn.execute("INSERT INTO user (name, country_id) VALUES ('Homer', 123)
                       RETURNING *")

如果你只想要得到的id

result = conn.execute("INSERT INTO user (name, country_id) VALUES ('Homer', 123)
                        RETURNING id")
[new_id] = result.fetchone()

【讨论】:

  • 绝对是我需要的。在这两种情况下,返回的对象都是 ResultProxy,所以我必须稍微修改一下代码(通过调用 fetchone())才能让它工作。
  • 或者,user.insert().returning(user.c.id).values({'name': 'Homer', 'country_id': 123})
  • 此解决方案不适用于sqlite。结果为sqlalchemy.exc.CompileError: RETURNING is not supported by this dialect's statement compiler.。在这种情况下,另一种解决方案 (lastrowid) 有效。
  • @ErwinBrandstetter 我明白这一点,但 sqlalchemy 的重点是数据库抽象,所以我只是注意到在这种情况下它可能是不可能的(获取 lastrowid)。
  • 为了澄清之前的 cmets,如果您修改查询以包含 RETURNING id,因此您有类似这样的内容:result_obj = conn.execute("INSERT INTO user (name, country_id) VALUES ('Homer', 123) RETURNING id") 那么您可以使用 fetchone() 获取最后插入的 id 并获取返回的元组中的项目:last_inserted_id = result_obj.fetchone()[0]
【解决方案2】:

用户lastrowid

result = conn.execute("INSERT INTO user (name, country_id) VALUES ('Homer', 123)")
result.lastrowid

【讨论】:

  • 对不起,我的办公桌上没有 pgsql,我用的是 mysql :)
  • 更具体地说,它不适用于没有 oid 的表,这是当前默认设置。无论如何,它通常不是您要寻找的 oid:返回是一种更好的解决方案。
  • 感谢 MySQL 解决方案
【解决方案3】:

当前 SQLAlchemy documentation 建议

result.inserted_primary_key 应该可以工作!

【讨论】:

    【解决方案4】:

    Python + SQLAlchemy

    提交后,您会在对象中更新 primary_key 列 ID(自动递增)。

    db.session.add(new_usr)
    db.session.commit() #will insert the new_usr data into database AND retrieve id
    idd = new_usr.usrID # usrID is the autoincremented primary_key column. 
    return jsonify(idd),201 #usrID = 12, correct id from table User in Database.
    

    【讨论】:

    • 对我来说,这只适用于我的模型类名称与 __tablename__ 相同的情况 - 如果它们不同,我在尝试访问 usrID 时会收到错误
    【解决方案5】:

    这个问题已经在stackoverflow上被问过很多次了,我所看到的没有一个答案是全面的。谷歌搜索“sqlalchemy insert get id of new row”会找到很多。

    SQLAlchemy 分为三个级别。 顶部:ORM。 中间:带有表类等的数据库抽象(DBA)。 底部:使用文本函数的 SQL。

    对于 OO 程序员来说,ORM 级别看起来很自然,但对于数据库程序员来说,它看起来很丑,而且 ORM 会阻碍。 DBA 层是一个不错的折衷方案。 SQL 层对于数据库程序员来说看起来很自然,而对于纯面向对象的程序员来说却是陌生的。

    每个级别都有自己的语法,相似但不同,足以令人沮丧。除此之外,网上的文档几乎太多了,很难找到答案。

    我将描述如何在我使用的 RDBMS 的 SQL 层获取插入的 id。

    Table: User(user_id integer primary autoincrement key, user_name string)
    conn: Is a Connection obtained within SQLAlchemy to the DBMS you are using.
    
    
    SQLite
    ======
    insstmt = text(
        '''INSERT INTO user (user_name)
        VALUES (:usernm) ''' )
    # Execute within a transaction (optional)
    txn = conn.begin()
    result = conn.execute(insstmt, usernm='Jane Doe')
    # The id!
    recid = result.lastrowid
    txn.commit()
    
    
    MS SQL Server
    =============
    insstmt = text(
        '''INSERT INTO user (user_name) 
        OUTPUT inserted.record_id
        VALUES (:usernm) ''' )
    txn = conn.begin()
    result = conn.execute(insstmt, usernm='Jane Doe')
    # The id!
    recid = result.fetchone()[0]
    txn.commit()
    
    
    MariaDB/MySQL
    =============
    insstmt = text(
        '''INSERT INTO user (user_name)
        VALUES (:usernm) ''' )
    txn = conn.begin()
    result = conn.execute(insstmt, usernm='Jane Doe')
    # The id!
    recid = conn.execute(text('SELECT LAST_INSERT_ID()')).fetchone()[0]
    txn.commit()
    
    
    Postgres
    ========
    insstmt = text(
        '''INSERT INTO user (user_name)
        VALUES (:usernm) 
        RETURNING user_id ''' )
    txn = conn.begin()
    result = conn.execute(insstmt, usernm='Jane Doe')
    # The id!
    recid = result.fetchone()[0]
    txn.commit()
    

    【讨论】:

    • 有趣,但无法让它在 sql server 上工作——使用 SA 和 pymssql。
    • 我使用的连接字符串是mssql+pyodbc://MIPLTP041/dbname?driver=SQL+Server+Native+Client+10.0。也许 pymssql 使用上面提到的其他协议之一?
    • 这行得通,谢谢!!
    【解决方案6】:
    result.inserted_primary_key
    

    为我工作。唯一需要注意的是,这会返回一个包含 last_insert_id 的列表。

    【讨论】:

      【解决方案7】:

      确保使用fetchrow/fetch 接收returning 对象

      insert_stmt = user.insert().values(name="homer", country_id="123").returning(user.c.id)
      
      row_id = await conn.fetchrow(insert_stmt)
      

      【讨论】:

        猜你喜欢
        • 2018-11-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-24
        相关资源
        最近更新 更多