Windows, python 3.7, SQLAlchemy 2.0.27
Имею:
запрос рабочий, но на MS SQL. Хочу преобразовать его с SQL на python ORM alchemy, чтобы вычислялся асинхронно и не городить временные таблицы в SQL. Начал писать:
но столкнулся с тем, что могу понять, как указать условие
.
В голове есть 2 варианта:
- сначала сделать соединение по товарам, а потом фильтроваться по количеству (первичный запрос вернет лишние данные).
- передать в запрос список условий с каждой парой товар-количество (будет большое избыточное условие).
Какой правильный подход?
Имею:
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 варианта:
- сначала сделать соединение по товарам, а потом фильтроваться по количеству (первичный запрос вернет лишние данные).
- передать в запрос список условий с каждой парой товар-количество (будет большое избыточное условие).
Какой правильный подход?