如何在Django中实现先取最大值再求和的嵌套聚合查询?
在Django中实现嵌套聚合查询(先取最大再求和)
问题分析
你尝试的第一种写法报错是因为Django不允许在同一个QuerySet中对聚合字段(如total)再次执行聚合操作,每次annotate与values的组合会重新触发分组,之前的聚合结果无法直接被后续聚合调用。
第二种子查询写法效率低下,是因为它生成了关联子查询(外层每行数据都会执行一次子查询),导致数据库执行成本指数级上升。
正确解决方案
我们可以分两步构建查询,让Django生成和你手写SQL结构一致的高效嵌套查询:
from django.db.models import Max, Sum # 1. 先获取每个地点+类型的最大金额,同时关联对应的州信息 max_per_location_type = daily_data.objects.filter( type__in=['purchases', 'returns'] ).values('location__state', 'location_id', 'type').annotate( max_amount=Max('amount') ) # 2. 按州和类型分组,对每个州+类型下的所有地点最大金额求和 final_result = max_per_location_type.values('location__state', 'type').annotate( total_max_amount=Sum('max_amount') ).order_by('location__state', 'type')
生成的SQL说明
这段代码会生成与你手写SQL几乎完全一致的查询,先通过子查询一次性计算所有地点+类型的最大金额,再在外层做分组求和:
SELECT "locations"."state", "daily_data"."type", SUM("max_amount") AS "total_max_amount" FROM ( SELECT "locations"."state", "daily_data"."location_id", "daily_data"."type", MAX("daily_data"."amount") AS "max_amount" FROM "daily_data" INNER JOIN "locations" ON ("daily_data"."location_id" = "locations"."id") WHERE "daily_data"."type" IN ('purchases', 'returns') GROUP BY "locations"."state", "daily_data"."location_id", "daily_data"."type" ) AS "subquery" GROUP BY "locations"."state", "daily_data"."type" ORDER BY "locations"."state" ASC, "daily_data"."type" ASC
这种写法避免了关联子查询的性能问题,执行效率和你手写的原生SQL完全一致。
获取结果
遍历查询结果即可得到你预期的格式:
for item in final_result: print(f"{item['location__state']},{item['type']},{item['total_max_amount']}")
内容的提问来源于stack exchange,提问作者JaWe
相关产品推荐
相关产品推荐

