SQL Alchemy - INSERT результаты запроса

Я ищу способ в SQLAlchemy сделать массовое INSERT, чьи строки являются результатом запроса. Я знаю, что в сеансе есть функция add, которую можно использовать для добавления отдельного объекта, но я не могу понять, как она работает с подзапросом.

Я знаю, что могу перебирать результаты подзапроса и add их по отдельности, но это может показаться несколько неэффективным. В моем случае я имею дело с потенциально очень большим набором данных, которые необходимо вставить.


person Mike    schedule 15.08.2011    source источник


Ответы (3)


Я вижу следующие варианты:

  1. using SA Model: create underlying objects with data loaded from the database, add them to session and commit.
    • Pros: if you have any AS Model level validation, you are able to use it; also you can insert into multiple tables if you model objects are mapped to multiple tables (Joined-Table Inheritance); is RDBMS independent
    • Минусы: самый дорогой
  2. using Insert statements: load data from the database into python and execute using Insert Expressions
  3. create data using solely RDBMS: bulk insert using RDBMS only bypassing SA and python altogether.
    • Pros: fastest
    • Минусы: не выполняется проверка бизнес-объектов; потенциально требуется реализация для РСУБД

Я бы предложил либо вариант 1), либо вариант 3).
На самом деле, если у вас нет проверки объектов и вы используете только одну СУБД, я бы придерживался варианта 3).

person van    schedule 16.08.2011
comment
спасибо за подробный ответ. Я думаю, что я собираюсь пойти с вариантом 3 - person Mike; 19.08.2011
comment
Я считаю, что часто задаваемые вопросы по SQLAlchemy также могут прояснить этот вопрос: -orm-and-it-s-really-slow" rel="nofollow noreferrer">docs.sqlalchemy.org/en/latest/faq/. - person Arthur Alvim; 20.04.2017

Я считаю, что единственный способ сделать это в SQLAlchemy - это выполнить необработанный оператор SQL с использованием Session.execute.

person jwegan    schedule 16.08.2011

Поскольку это лучший результат в Google по этому распространенному вопросу, и на самом деле существует гораздо лучшее решение, вот обновленный ответ. Вы можете использовать метод Insert.from_select(). Хотя его трудно найти, он задокументирован здесь.


Быстрый учебник

При работе с объектами Table вы можете использовать что-то вроде:

>>> from sqlalchemy.sql import select
>>> stmt = TargetTable.insert().from_select([TargetTable.c.user_id, TargetTable.c.user_name],
                                            select([SrcTable.c.user_id, SrcTable.c.user_name]))

>>> print(stmt)
INSERT INTO "TargetTable" (user_id, user_name) SELECT "SrcTable".user_id, "SrcTable".user_name
FROM "SrcTable"

Наконец, выполните с engine.execute(stmt) или подобным.

Окончательный выходной оператор компилируется SQLAlchemy в зависимости от диалекта, используемого в движке. Здесь я использовал диалект SQLite.

Это успешно позволяет избежать загрузки каких-либо данных в объекты Python, и позволяет механизму базы данных эффективно обрабатывать все. Ура!

В отличие от использования текстовых операторов SQL с text() этот метод также независим от СУБД, поскольку он по-прежнему использует язык выражений SQLAlchemy, как описано здесь. Этот язык обеспечивает компиляцию на правильный диалект при выполнении.

Использование ORM-таблиц

Исходный вопрос указывает на вариант использования, когда ORM используется для взаимодействия с базой данных. Вы, вероятно, также определили свои таблицы, используя базу ORM. Метаданные, хранящиеся в этих объектах, теперь работают немного по-другому. Поэтому немного изменим пример:

>>> from sqlalchemy.sql import select, insert
>>> stmt = insert(TargetTable).from_select([TargetTable.user_id, TargetTable.user_name],
                                           select([SrcTable.user_id, SrcTable.user_name]))
>>> engine.execute(stmt)
INFO sqlalchemy.engine.base.Engine INSERT INTO "TargetTable" (user_id, user_name) SELECT "SrcTable".user_id, "SrcTable".user_name
FROM "SrcTable"

Ну посмотри на это. На самом деле это даже сделало его немного проще.

И это будет намного быстрее.


P.S. Вот еще один секрет из документов. Хотите использовать операторы sql WITH таким же динамическим образом? Вы можете сделать это с помощью "CTE"

person Trezorro    schedule 10.04.2020