Вставка строк с помощью ядра

При использовании Core оператор SQL INSERT генерируется с помощью функции insert() - эта функция генерирует новый экземпляр Insert, который представляет собой оператор INSERT в SQL, добавляющий новые данные в таблицу.

ORM Readers - Способ вставки строк в базу данных с точки зрения ORM использует объектно-ориентированные API для объекта Session, известного как процесс unit of work, и довольно сильно отличается от подхода, описанного здесь только для Core. В последующих разделах, более ориентированных на ORM, начиная с Вставка строк с помощью ORM, после разделов по языку выражения, это будет представлено.

Конструкция SQL-выражения insert()

Простой пример Insert, иллюстрирующий целевую таблицу и предложение VALUES одновременно:

>>> from sqlalchemy import insert
>>> stmt = insert(user_table).values(name="spongebob", fullname="Spongebob Squarepants")

Приведенная выше переменная stmt является экземпляром Insert. Большинство SQL-выражений можно перевести в строку на месте, чтобы увидеть общую форму того, что получается:

>>> print(stmt)
INSERT INTO user_account (name, fullname) VALUES (:name, :fullname)

Стрингированная форма создается путем создания Compiled формы объекта, которая включает специфическое для базы данных строковое SQL-представление оператора; мы можем получить этот объект непосредственно с помощью метода ClauseElement.compile():

>>> compiled = stmt.compile()

Наша конструкция Insert является примером «параметризованной» конструкции, показанной ранее в Параметры отправки; для просмотра name и fullname bound parameters, они также доступны из конструкции Compiled:

>>> compiled.params
{'name': 'spongebob', 'fullname': 'Spongebob Squarepants'}

Выполнение заявления

Вызвав оператор, мы можем INSERT строку в user_table. SQL INSERT, а также связанные параметры можно увидеть в журнале SQL:

>>> with engine.connect() as conn:
...     result = conn.execute(stmt)
...     conn.commit()
BEGIN (implicit) INSERT INTO user_account (name, fullname) VALUES (?, ?) [...] ('spongebob', 'Spongebob Squarepants') COMMIT

В своей простой форме оператор INSERT не возвращает никаких строк, и если вставляется только одна строка, он обычно включает возможность возврата информации о значениях по умолчанию на уровне столбцов, которые были созданы во время INSERT этой строки, чаще всего целочисленное значение первичного ключа. В приведенном выше случае первая строка в базе данных SQLite обычно возвращает 1 для первого целочисленного значения первичного ключа, которое мы можем получить с помощью аксессора CursorResult.inserted_primary_key:

>>> result.inserted_primary_key
(1,)

Совет

CursorResult.inserted_primary_key возвращает кортеж, поскольку первичный ключ может содержать несколько столбцов. Это известно как composite primary key. CursorResult.inserted_primary_key должен всегда содержать полный первичный ключ только что вставленной записи, а не просто значение типа «cursor.lastrowid», а также должен быть заполнен независимо от того, использовался ли «автоинкремент» или нет, поэтому для выражения полного первичного ключа это кортеж.

Изменено в версии 1.4.8: кортеж, возвращаемый CursorResult.inserted_primary_key, теперь является именованным кортежем, выполняемым путем возвращения его в виде объекта Row.

INSERT обычно генерирует предложение «значения» автоматически

В приведенном выше примере использовался метод Insert.values() для явного создания пункта VALUES оператора SQL INSERT. На самом деле этот метод имеет несколько вариантов, которые позволяют использовать специальные формы, такие как несколько строк в одном операторе и вставка выражений SQL. Однако обычный способ использования Insert заключается в том, что предложение VALUES генерируется автоматически из параметров, переданных методу Connection.execute(); ниже мы выполним INSERT еще двух строк, чтобы проиллюстрировать это:

>>> with engine.connect() as conn:
...     result = conn.execute(
...         insert(user_table),
...         [
...             {"name": "sandy", "fullname": "Sandy Cheeks"},
...             {"name": "patrick", "fullname": "Patrick Star"},
...         ],
...     )
...     conn.commit()
BEGIN (implicit) INSERT INTO user_account (name, fullname) VALUES (?, ?) [...] (('sandy', 'Sandy Cheeks'), ('patrick', 'Patrick Star')) COMMIT

Приведенное выше выполнение имеет форму «executemany», впервые показанную в Отправка нескольких параметров, однако, в отличие от использования конструкции text(), нам не пришлось писать SQL. Передавая словарь или список словарей в метод Connection.execute() в сочетании с конструкцией Insert, Connection гарантирует, что переданные имена столбцов будут выражены в предложении VALUES конструкции Insert автоматически.

Deep Alchemy

Привет, добро пожаловать в первый выпуск Глубокой алхимии. Человек слева известен как Алхимик, и вы заметите, что он не волшебник, поскольку остроконечная шляпа не торчит вверх. Алхимик приходит, чтобы описать вещи, которые обычно более продвинуты и/или сложны и, кроме того, обычно не нужны, но по какой-то причине он считает, что вы должны знать об этой вещи, которую может сделать SQLAlchemy.

В этом издании, с целью получения интересных данных и в address_table, ниже приведен более продвинутый пример, иллюстрирующий, как метод Insert.values() может быть использован явно и в то же время включать для дополнительных VALUES, генерируемых из параметров. Строится scalar subquery с использованием конструкции select(), представленной в следующем разделе, а параметры, используемые в подзапросе, задаются с помощью явного связанного имени параметра, установленного с помощью конструкции bindparam().

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

>>> from sqlalchemy import select, bindparam
>>> scalar_subq = (
...     select(user_table.c.id)
...     .where(user_table.c.name == bindparam("username"))
...     .scalar_subquery()
... )

>>> with engine.connect() as conn:
...     result = conn.execute(
...         insert(address_table).values(user_id=scalar_subq),
...         [
...             {"username": "spongebob", "email_address": "spongebob@sqlalchemy.org"},
...             {"username": "sandy", "email_address": "sandy@sqlalchemy.org"},
...             {"username": "sandy", "email_address": "sandy@squirrelpower.org"},
...         ],
...     )
...     conn.commit()
BEGIN (implicit) INSERT INTO address (user_id, email_address) VALUES ((SELECT user_account.id FROM user_account WHERE user_account.name = ?), ?) [...] (('spongebob', 'spongebob@sqlalchemy.org'), ('sandy', 'sandy@sqlalchemy.org'), ('sandy', 'sandy@squirrelpower.org')) COMMIT

ВСТАВИТЬ… ИЗ SELECT

Конструкция Insert может составлять INSERT, который получает строки непосредственно из SELECT, используя метод Insert.from_select():

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
>>> insert_stmt = insert(address_table).from_select(
...     ["user_id", "email_address"], select_stmt
... )
>>> print(insert_stmt)
INSERT INTO address (user_id, email_address) SELECT user_account.id, user_account.name || :name_1 AS anon_1 FROM user_account

ВСТАВКА… ВОЗВРАЩЕНИЕ

Предложение RETURNING для поддерживаемых бэкендов используется автоматически для получения последнего вставленного значения первичного ключа, а также значений по умолчанию сервера. Однако условие RETURNING может быть также задано явно с помощью метода Insert.returning(); в этом случае объект Result, возвращаемый при выполнении оператора, содержит строки, которые могут быть извлечены:

>>> insert_stmt = insert(address_table).returning(
...     address_table.c.id, address_table.c.email_address
... )
>>> print(insert_stmt)
INSERT INTO address (id, user_id, email_address) VALUES (:id, :user_id, :email_address) RETURNING address.id, address.email_address

Его также можно комбинировать с Insert.from_select(), как в примере ниже, который основан на примере, приведенном в ВСТАВИТЬ… ИЗ SELECT:

>>> select_stmt = select(user_table.c.id, user_table.c.name + "@aol.com")
>>> insert_stmt = insert(address_table).from_select(
...     ["user_id", "email_address"], select_stmt
... )
>>> print(insert_stmt.returning(address_table.c.id, address_table.c.email_address))
INSERT INTO address (user_id, email_address) SELECT user_account.id, user_account.name || :name_1 AS anon_1 FROM user_account RETURNING address.id, address.email_address

Совет

Функция RETURNING также поддерживается операторами UPDATE и DELETE, которые будут представлены позже в этом учебнике. Функция RETURNING обычно [1] поддерживается только для выполнения операторов, которые используют один набор связанных параметров; то есть она не работает с формой «executemany», представленной в Отправка нескольких параметров. Кроме того, некоторые диалекты, такие как диалект Oracle, позволяют RETURNING возвращать только одну строку в целом, что означает, что он не будет работать с «INSERT…FROM SELECT» или с формами с несколькими строками Update или Delete.

См.также

Insert - в документации SQL Expression API

Вернуться на верх