Как обрезать и вставить в одну транзакцию, используя sqlalchemy?

0

У меня есть production_table и stage_table. У меня есть скрипт python, который работает в течение нескольких часов и генерирует данные в stage_table. Я хочу, чтобы в конце сценария stage_table данные COPY с stage_table на production_table.

В основном это то, что я хочу:

1. TRUNCATE production_table
2. COPY production_table from stage_table

Это мой код:

from sqlalchemy import create_engine
from sqlalchemy.sql import text as sa_text
engine = create_engine("mysql+pymysql://  AMAZON AWS")
engine.execute(sa_text('''TRUNCATE TABLE {1}; COPY TABLE {1} from {0}'''.format(stage_table, production_table)).execution_options(autocommit=True))

Это должно генерировать:

TRUNCATE TABLE production_table; COPY TABLE production_table from stage_table

Однако это не сработает.

sqlalchemy.exc.ProgrammingError: (pymysql.err.ProgrammingError) (1064, u "У вас есть ошибка в синтаксисе SQL;

Как я могу заставить его работать? и как я могу убедиться, что TRUNCATE и COPY вместе. Я не хочу, чтобы TRUNCATE произошел, если COPY прерывается.

  • 0
    Есть ли в MySQL оператор COPY?
  • 0
    @ IljaEverilä Это может быть частью проблемы ..? В день нужно импортировать 2 млн записей ... Операция вставки может быть очень медленной .. именно поэтому была создана копия. не так ли?
Показать ещё 2 комментария
Теги:
sqlalchemy

1 ответ

1
Лучший ответ

Обычный способ обработки нескольких операторов в одной транзакции в SQLAlchemy заключался бы в том, чтобы начать явную транзакцию и выполнить каждый оператор в ней:

with engine.begin() as conn:
    conn.execute(statement_1)
    conn.execute(statement_2)
    ...

Что касается вашей первоначальной попытки, в MySQL нет инструкции COPY. У некоторых других СУБД есть что-то в этом роде. Кроме того, не все драйверы DB-API поддерживают несколько операторов в одном запросе или команде, по крайней мере, из коробки, что, похоже, также имеет место здесь. См. Эту проблему и соответствующую заметку в журнале изменений PyMySQL.

Самая большая проблема заключается в том, что не все заявления в MySQL могут быть отброшены назад, из которых наиболее распространенными являются заявления DDL. Другими словами, вы просто не можете выполнить TRUNCATE [TABLE]... в той же транзакции, что и следующий INSERT INTO... и должны разработать приложение вокруг этого ограничения. Как было предложено в комментариях Кристианом В., вы могли бы создать совершенно новую таблицу из своей промежуточной таблицы и переименовать ее или просто поменять местами производственные и промежуточные таблицы. RENAME TABLE... нельзя откат, но, по крайней мере, вы уменьшите окно ошибки и сможете отменить изменения, поскольку исходная производственная таблица все равно будет находиться под новым именем. Затем вы можете удалить исходную производственную таблицу, когда все остальное будет сделано. Здесь что-то, что демонстрирует эту идею, но требует ручного вмешательства, если что-то пойдет не так:

# No point in faking transactions here, since MySQL in use.
engine.execute("CREATE TABLE new_production AS SELECT * FROM stage_table")
engine.execute("RENAME TABLE production_table TO old_production")
engine.execute("RENAME TABLE new_production TO production_table")
# Point of no return:
engine.execute("DROP TABLE old_production")
  • 0
    Куда идет .execution_options (autocommit = True)?
  • 0
    Это не нужно в этом случае. Вы явно управляете транзакцией, используя оператор with, по сравнению с autocommit.
Показать ещё 10 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню