Sqlalchemy - 如何在执行 groupby 函数时使用 joinload

问题描述 投票:0回答:1

我正在尝试将负载(供应商)加入到我的主对象(service_order),同时还运行 sum 函数和 groupby。下面是我尝试运行的代码。

async def search_service_orders(
    session: AsyncSession,
    service_order_number: str = None,
    source_service_order_number: str = None,
    limit: int = 20,
    offset: int = 0,
) -> Sequence[ServiceOrderSearchModel]:
    async with session:
        statement = (
            select(
                DBServiceOrder,
                func.sum(DBServiceOrderItem.unit_price).label("total_price"),
            )
            .options(joinedload(DBServiceOrder.vendor))
            .outerjoin(
                DBServiceOrderItem,
                DBServiceOrder.service_order_id == DBServiceOrderItem.service_order_id,
            )
            .group_by(DBServiceOrder)
        )

        if service_order_number is not None:
            statement = statement.where(
                DBServiceOrder.service_order_number.ilike(f"%{service_order_number}%")
            )
        if source_service_order_number is not None:
            statement = statement.where(
                DBServiceOrder.source_service_order_number.ilike(
                    f"%{source_service_order_number}%"
                )
            )

        statement = statement.limit(limit).offset(offset)
        result = await session.execute(statement)
        list_of_service_orders = result.all()

这会导致错误:

ORA-00979: not a GROUP BY expression

下面是生成的sql。

[SQL: SELECT service_order.service_order_id, service_order.authorized_by, service_order.authorized_date, service_order.bill_to_addr, service_order.cancel_date, service_order.cancel_by, service_order.expected_delivery_date, service_order.orderd_by, service_order.order_date, service_order.quote_estimate_number, service_order.service_order_number, service_order.service_type, service_order.service_status, service_order.ship_to_addr, service_order.shipping_method, service_order.source_service_order_number, service_order.vendor_id, service_order.created_by, service_order.create_ts, service_order.updated_by, service_order.update_ts, sum(service_order_item.unit_price) AS total_price, vendor_1.vendor_id AS vendor_id_1, 
vendor_1.address_1, vendor_1.address_2, vendor_1.city, vendor_1.comment_txt, vendor_1.company_type, vendor_1.company_name, vendor_1.eog_msa_fl, vendor_1.fax_number, vendor_1.is_active, vendor_1.postal_code, vendor_1.phone_number, vendor_1.state_nm, vendor_1.vendor_number, vendor_1.vendor_uuid, vendor_1.created_by AS created_by_1, vendor_1.created_date, vendor_1.updated_by AS updated_by_1, vendor_1.updated_date
FROM service_order LEFT OUTER JOIN service_order_item ON service_order.service_order_id = service_order_item.service_order_id LEFT OUTER JOIN vendor vendor_1 ON vendor_1.vendor_id = service_order.vendor_id
WHERE lower(service_order.service_order_number) LIKE lower(:service_order_number_1) GROUP BY service_order.service_order_id, service_order.authorized_by, service_order.authorized_date, service_order.bill_to_addr, service_order.cancel_date, 
service_order.cancel_by, service_order.expected_delivery_date, service_order.orderd_by, service_order.order_date, service_order.quote_estimate_number, service_order.service_order_number, service_order.service_type, service_order.service_status, service_order.ship_to_addr, service_order.shipping_method, service_order.source_service_order_number, service_order.vendor_id, service_order.created_by, service_order.create_ts, service_order.updated_by, service_order.update_ts        
 OFFSET 0 ROWS
 FETCH FIRST 20 ROWS ONLY]
[parameters: {'service_order_number_1': '%SO%'}]

然后我将 DBVendor 对象添加到 groupby 语句中,如下所示:

.group_by(DBServiceOrder, DBVendor)

导致错误:

sqlalchemy.exc.DatabaseError: (oracledb.exceptions.DatabaseError) ORA-00904: "VENDOR"."UPDATED_DATE": invalid identifier

这个错误没有任何意义,因为我的所有表都已正确定义,并且我能够在其他查询上与供应商连接加载。下面是这个错误的sql查询:

[SQL: SELECT service_order.service_order_id, service_order.authorized_by, service_order.authorized_date, service_order.bill_to_addr, service_order.cancel_date, service_order.cancel_by, service_order.expected_delivery_date, service_order.orderd_by, service_order.order_date, service_order.quote_estimate_number, service_order.service_order_number, service_order.service_type, service_order.service_status, service_order.ship_to_addr, service_order.shipping_method, service_order.source_service_order_number, service_order.vendor_id, service_order.created_by, service_order.create_ts, service_order.updated_by, service_order.update_ts, sum(service_order_item.unit_price) AS total_price, vendor_1.vendor_id AS vendor_id_1, 
vendor_1.address_1, vendor_1.address_2, vendor_1.city, vendor_1.comment_txt, vendor_1.company_type, vendor_1.company_name, vendor_1.eog_msa_fl, vendor_1.fax_number, vendor_1.is_active, vendor_1.postal_code, vendor_1.phone_number, vendor_1.state_nm, vendor_1.vendor_number, vendor_1.vendor_uuid, vendor_1.created_by AS created_by_1, vendor_1.created_date, vendor_1.updated_by AS updated_by_1, vendor_1.updated_date
FROM service_order LEFT OUTER JOIN service_order_item ON service_order.service_order_id = service_order_item.service_order_id LEFT OUTER JOIN vendor vendor_1 ON vendor_1.vendor_id = service_order.vendor_id
WHERE lower(service_order.service_order_number) LIKE lower(:service_order_number_1) GROUP BY service_order.service_order_id, service_order.authorized_by, service_order.authorized_date, service_order.bill_to_addr, service_order.cancel_date, 
service_order.cancel_by, service_order.expected_delivery_date, service_order.orderd_by, service_order.order_date, service_order.quote_estimate_number, service_order.service_order_number, service_order.service_type, service_order.service_status, service_order.ship_to_addr, service_order.shipping_method, service_order.source_service_order_number, service_order.vendor_id, service_order.created_by, service_order.create_ts, service_order.updated_by, service_order.update_ts, vendor.vendor_id, vendor.address_1, vendor.address_2, vendor.city, vendor.comment_txt, vendor.company_type, vendor.company_name, vendor.eog_msa_fl, vendor.fax_number, vendor.is_active, vendor.postal_code, vendor.phone_number, vendor.state_nm, vendor.vendor_number, vendor.vendor_uuid, vendor.created_by, vendor.created_date, vendor.updated_by, vendor.updated_date   
 OFFSET 0 ROWS
 FETCH FIRST 20 ROWS ONLY]
[parameters: {'service_order_number_1': '%SO%'}]

有人知道如何在使用 joinload 的同时执行 func.sum 和 groupby 吗?

我还尝试在 service_order 表定义中添加惰性关系,但它给了我与上面相同的错误......

python oracle sqlalchemy
1个回答
0
投票

我能够通过使用 subqueryload 来解决这个问题。

statement = (
            select(
                DBServiceOrder,
                func.sum(DBServiceOrderItem.unit_price).label("total_price"),
            )
            .outerjoin(
                DBServiceOrderItem,
                DBServiceOrder.service_order_id == DBServiceOrderItem.service_order_id,
            )
            .group_by(DBServiceOrder)
            .options(subqueryload(DBServiceOrder.vendor))
        )
© www.soinside.com 2019 - 2024. All rights reserved.