SqlAlchemy: получение идентификатора последней записи

Я использую SQLAlchemy без ORM, то есть используя созданные вручную SQL statememts, чтобы напрямую взаимодействовать с бэкэнд-бэбом. В этом случае я использую PG в качестве моего бэкэнда db (psycopg2 как драйвер DB) - я не знаю, влияет ли это на ответ.

У меня есть такие утверждения (для краткости предположим, что conn является действительным соединением с db):

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

Предположим также, что таблица пользователя состоит из столбцов (id [SERIAL PRIMARY KEY], name, country_id)

Как я могу получить идентификатор нового пользователя (в идеале, не ударяя db снова?)

Ответ 1

Возможно, вы можете использовать предложение RETURNING оператора INSERT следующим образом:

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

Если вам нужен только результирующий id:

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

Ответ 2

Пользователь lastrowid

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

Ответ 3

В текущей документации SQLAlchemy

result.inserted_primary_key должен работать!

Ответ 4

result.inserted_primary_key

работал на меня. Единственное, на что следует обратить внимание, это то, что он возвращает список, содержащий этот last_insert_id.

Ответ 5

Убедитесь, что вы используете fetchrow/fetch для получения объекта returning

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

row_id = await conn.fetchrow(insert_stmt)

Ответ 6

этот вопрос задавался много раз на stackoverflow, и ни один ответ, который я видел, не является исчерпывающим. Погуглив "sqlalchemy insert get id of new row", многие из них поднимаются.

Существует три уровня SQLAlchemy. Вверху: ОРМ. Средняя: абстракция базы данных (DBA) с классами таблиц и т.д. Внизу: SQL с использованием текстовой функции.

Для OO-программиста уровень ORM выглядит естественным, но для программиста базы данных он выглядит уродливо и мешает ORM. Уровень DBA - это хороший компромисс. Уровень SQL выглядит естественным для программистов баз данных и будет выглядеть чуждым только для программиста OO.

Каждый уровень имеет свой собственный синтаксис, похожий, но достаточно различающийся, чтобы расстраивать. Кроме того, в Интернете почти слишком много документации, очень сложно найти ответ.

Я опишу, как получить вставленный идентификатор на уровне SQL для СУБД, которую я использую.

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()