SqlAlchemy统计全部与已完成请求无结果问题及查询优化咨询
问题分析与解决方案
原代码存在的问题
- 返回结果重复:主查询包含
Requests表,会导致每个用户有多少条请求就返回多少行,而我们需要的是每个用户一行的统计数据,不符合需求。 - done统计显示为空:
sq_done通过outerjoin关联后,没有done状态请求的用户,其done_num会是null,看起来像“无结果”,而非预期的0。 - 未利用关联关系:没有用到
Users与Requests的关联,导致查询结构冗余。
修复方案1:优化子查询+处理空值
调整主查询以Users为核心,用coalesce将空值转为0,同时简化关联逻辑:
from sqlalchemy import func, coalesce # 总请求数子查询 sq_all = db.session.query( Requests.uid, func.count(Requests.id).label('requests_num') ).group_by(Requests.uid).subquery() # done状态请求数子查询 sq_done = db.session.query( Requests.uid, func.count(Requests.id).label('done_num') ).filter(Requests.status == RequestStatusEnum.done).group_by(Requests.uid).subquery() # 主查询:按用户维度聚合,处理空值 query = db.session.query( Users, UserInfos, sq_all.c.requests_num, # 将null转为0,确保无done请求的用户显示0 coalesce(sq_done.c.done_num, 0).label('done_num') ).join(UserInfos, Users.id == UserInfos.uid) # 若用户可能无UserInfos,改用outerjoin .outerjoin(sq_all, Users.id == sq_all.c.uid) .outerjoin(sq_done, Users.id == sq_done.c.uid) .group_by(Users.id, UserInfos.id, sq_all.c.requests_num)
修复方案2:利用Users的requests关联(更简洁)
既然Users已经有requests关联关系,直接通过关联做聚合,无需单独子查询:
from sqlalchemy import func, case query = db.session.query( Users, UserInfos, # 统计总请求数,利用关联关系 func.count(Users.requests.id).label('requests_num'), # 统计done状态请求数:符合条件记1,否则0,求和 func.sum( case( (Users.requests.status == RequestStatusEnum.done, 1), else_=0 ) ).label('done_num') ).join(UserInfos, Users.id == UserInfos.uid) .outerjoin(Users.requests) # 左连接确保无请求的用户也被统计 .group_by(Users.id, UserInfos.id)
关键说明
- 方案2更符合SQLAlchemy的ORM设计思路,代码更简洁易维护。
- 两种方案都解决了“done统计无结果”的问题:要么用
coalesce转空值为0,要么用case+sum直接统计0值。 - 主查询以
Users为核心,确保每个用户只返回一行统计数据,避免重复。
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

