Запрос MS SQL в SQLAlchemy ORM.

Pavel R.

Новичок
Пользователь
Дек 30, 2024
1
0
1
Windows, python 3.7, SQLAlchemy 2.0.27

Имею:
Python:
def check_conditions_goods_MA_old(db, ma: MarketingActivity, arrGoods: List[NormalizedData_Good])->bool:
    
    # Подготавливаем данные для вставки
    values = []
    params = {}
    
    for i, line in enumerate(arrGoods):
        values.append(f'(:ref_{i}, :quantity_{i})')
        params[f'ref_{i}'] = line.good.code
        params[f'quantity_{i}'] = line.quantity
    params["MA_Ref"] = ma.ref
        
    valuesSQL = ', '.join(values)
    queryPre    = f"""  -- Удаляем временные таблицы, если существуют
                DROP TABLE IF EXISTS #InputTable;
                DROP TABLE IF EXISTS #Goods;
                DROP TABLE IF EXISTS ##MA_FilterQuantity;
                DROP TABLE IF EXISTS ##MA_FilterGroupsVarious;
                -- Создаем временную таблицу
                CREATE TABLE #InputTable (good_code numeric(7), quantity integer);
                \
                INSERT INTO #InputTable (good_code, quantity)
                VALUES {valuesSQL};
                \
                SELECT
                    Goods.Ref AS Ref,
                    InputTable.Quantity AS Quantity   
                INTO #Goods
                FROM
                    #InputTable AS InputTable
                    INNER JOIN Goods AS Goods
                    ON InputTable.good_code = Goods.Code
                WHERE
                    InputTable.Quantity > 0;   
                \
                SELECT
                    MA.Ref AS MA,
                    Goods.Ref AS Good,
                    MA_GG.KeyField AS KeyField,
                    MA_GG.Quantity AS Quantity,
                    MA_GG.VariousSKU AS VariousSKU,
                    MA_GG.QuantityVarious AS QuantityVarious
                INTO ##MA_FilterQuantity
                FROM
                    _ref_MarketingActivities AS MA
                    INNER JOIN _ref_MarketingActivities_Goods AS MA_Goods
                    ON MA.Ref = MA_Goods.MarketingActivity
                    INNER JOIN _ref_MarketingActivities_GroupsOfGoods AS MA_GG
                    ON MA.Ref = MA_GG.MarketingActivity
                        AND MA_Goods.KeyField = MA_GG.keyField
                    INNER JOIN #Goods AS Goods
                    ON MA_Goods.Element = Goods.Ref
                WHERE
                    MA.Ref = :MA_Ref
                    AND (Goods.Quantity >= MA_GG.Quantity
                        OR Goods.Quantity >= MA_GG.QuantityVarious);
                \
                SELECT
                    MA_FilterQuantity.MA,
                    MA_FilterQuantity.KeyField,
                    MA_FilterQuantity.VariousSKU,
                    COUNT(DISTINCT MA_FilterQuantity.Good) AS QuantitySKU
                INTO ##MA_FilterGroupsVarious   
                FROM
                    ##MA_FilterQuantity AS MA_FilterQuantity
                WHERE
                    MA_FilterQuantity.Quantity >= MA_FilterQuantity.QuantityVarious     
                GROUP BY
                    MA_FilterQuantity.MA,
                    MA_FilterQuantity.KeyField,
                    MA_FilterQuantity.VariousSKU
                HAVING
                    COUNT(DISTINCT MA_FilterQuantity.Good) >= MA_FilterQuantity.VariousSKU;"""
    
    queryMain = f"""SELECT DISTINCT
                    MA_FilterQuantity.MA
                FROM
                    ##MA_FilterQuantity AS MA_FilterQuantity
                WHERE
                    MA_FilterQuantity.VariousSKU = 0
                    AND MA_FilterQuantity.QuantityVarious = 0
                \
                UNION
                \
                SELECT DISTINCT
                    MA_FilterGroupsVarious.MA
                FROM
                    ##MA_FilterGroupsVarious AS MA_FilterGroupsVarious;"""
    
    queryPost = f"""
                DROP TABLE IF EXISTS #InputTable;
                DROP TABLE IF EXISTS #Goods;
                DROP TABLE IF EXISTS ##MA_FilterQuantity;
                DROP TABLE IF EXISTS ##MA_FilterGroupsVarious;"""
    try:
        with engine.begin() as conn:
            # Выполняем подготовительный запрос
            logging.info(text(queryPre))
            conn.execute(text(queryPre), params)
            # Обрабатываем результаты
            data = conn.execute(text(queryMain)).fetchall()
            result = len(data) > 0
            #logging.info(f'Результат check_ConditionsGoodsMA {ma.code}: {result}')
            #logging.info('Удаляем временные таблицы check_ConditionsGoodsMA.')
            conn.execute(text(queryPost))
            
            return result
        
    except Exception as e:
        logging.error(f'Ошибка при выполнении запросов: {e}')
        raise e

запрос рабочий, но на MS SQL. Хочу преобразовать его с SQL на python ORM alchemy, чтобы вычислялся асинхронно и не городить временные таблицы в SQL. Начал писать:

Python:
async def check_conditions_goods_MA(db, ma: MarketingActivity, arrGoods: List[NormalizedData_Good])->bool:
    query = select(
                    MA_Goods.element,
                    MA_Goods.key_field,
                    MA_GroupsOfGoods.quantity,
                    MA_GroupsOfGoods.quantity_various,
                    MA_GroupsOfGoods.various_sku
            .join(MA_GroupsOfGoods, MA_Goods.key_field == MA_GroupsOfGoods.key_field)
            .join(arrGoods, and_(
                                MA_Goods.element == arrGoods.good,
                                or_(
                                    arrGoods.Quantity >= MA_GroupsOfGoods.Quantity,
                                    arrGoods.Quantity >= MA_GroupsOfGoods.QuantityVarious
                                )
                            )
                )
            .where(
                and_(MA_Goods.marketing_activity == ma,
                     MA_Goods.element.in_(good.ref for good in arrGoods), 
                )
            )
    )
    results = await db.execute(query)
    return results.scalars().all()
но столкнулся с тем, что могу понять, как указать условие
Python:
MA_Goods.element == arrGoods.good,
                                or_(
                                    arrGoods.Quantity >= MA_GroupsOfGoods.Quantity,
                                    arrGoods.Quantity >= MA_GroupsOfGoods.QuantityVarious
.

В голове есть 2 варианта:
- сначала сделать соединение по товарам, а потом фильтроваться по количеству (первичный запрос вернет лишние данные).
- передать в запрос список условий с каждой парой товар-количество (будет большое избыточное условие).

Какой правильный подход?
 

Форум IT Специалистов