Как написать UPDATE ИЗ без подзапроса в SQLAlchemy для PostgreSQL

#python #postgresql #sqlalchemy

#python #postgresql #sqlalchemy

Вопрос:

Я пишу запрос, который обновляет столбец таблицы, вычисляя разницу между его значением и столбцом из другой таблицы. В необработанном SQL это выглядит следующим образом:

 UPDATE
    products
SET
    quantity = products.quantity - order_items.quantity
FROM
    order_items
WHERE
    order_items.order_id = %(order_id_1) s
    AND products.code = order_items.product_code;
  

Я проверил документацию по SQLAlchemy и нашел раздел о update выражении:

Предложение WHERE может ссылаться на несколько таблиц. Для баз данных, которые поддерживают это, будет сгенерировано предложение UPDATE FROM, или в MySQL, обновление с несколькими таблицами. Оператор завершится ошибкой в базах данных, которые не поддерживают операторы обновления с несколькими таблицами.

Я попытался реализовать запрос, как указано в документации:

 query = (
        products_table.update()
        .values(quantity=products_table.c.quantity - order_items_table.c.quantity)
        .where(
            products_table.c.code
            == select([order_items_table.c.product_code])
            .where(
                and_(
                    order_items_table.c.order_id == order_id,
                    order_items_table.c.product_code == products_table.c.code,
                )
            )
            .as_scalar()
        )
    )
  

Но вместо краткого UPDATE ... SET ... FROM выражения я получил это:

 from sqlalchemy.dialects import postgresql
str(query.compile(dialect=postgresql.dialect()))
  
 UPDATE
    products
SET
    quantity =(products.quantity - order_items.quantity)
WHERE
    products.code = (
        SELECT
            order_items.product_code
        FROM
            order_items
        WHERE
            order_items.order_id = %(order_id_1) s
            AND order_items.product_code = products.code
    )
  

Более того, этот SQL-запрос не совсем корректен и не содержит требуемого FROM оператора.

Поэтому я пытаюсь понять, что не так с моим выражением запроса и возможно ли вообще реализовать эквивалент необработанного SQL в SQLAlchemy без подзапроса. Есть идеи?

Версии

  • ОС: macOS
  • Python: 3.8.x
  • SQLAlchemy: 1.3.20
  • База данных: PostgreSQL 11.x

Заранее спасибо!

Ответ №1:

Кажется, я неправильно прочитал документацию. Ссылка, которую я опубликовал, объясняет обратное и предоставляет примеры написания запросов для баз данных, которые не поддерживают UPDATE FROM .

Я только что написал следующий запрос:

 query = (
    products_table.update()
    .values(quantity=products_table.c.quantity - order_items_table.c.quantity)
    .where(products_table.c.code == order_items_table.c.product_code)
    .where(order_items_table.c.order_id == order_id)
)
  

и он генерирует правильный SQL:

 UPDATE
    products
SET
    quantity =(products.quantity - order_items.quantity)
FROM
    order_items
WHERE
    products.code = order_items.product_code
    AND order_items.order_id = %(order_id_1) s