如何用Django ORM实现MariaDB按星期分组的营收占比查询
我来帮你解决这个Django ORM实现营收占比的问题!先分析下你遇到的核心问题,再给出几种可行的解决方案:
问题根源
你原始的MariaDB SQL逻辑是先按周几分组计算每组营收,再用每组营收除以整张表的总营收得到占比。之前的尝试失败原因:
- RawSQL写法:你直接在
values()里用ExtractIsoWeekDay,导致Django没有正确触发GROUP BY逻辑,所以只返回了单个值; - Window函数写法:直接用
Sum('revenue')/Window(Sum('revenue'))时,窗口函数是在分组前的全量数据上计算,而非分组后的总和,所以结果错误。
解决方案
解法1:用子查询获取总营收(兼容性最好)
这种方法先通过子查询一次性获取整张表的总营收,再分组计算每组占比,逻辑清晰且兼容大多数Django版本:
from django.db.models import Sum, F, ExtractIsoWeekDay, Subquery # 用Subquery获取总营收(避免两次数据库查询) total_revenue_subq = Subquery( Orders.objects.values('id') # 任意字段,仅用于触发聚合 .annotate(total=Sum('revenue')) .values('total')[:1] ) # 分组计算营收占比 share = ( Orders.objects .annotate(week_day=ExtractIsoWeekDay('date')) # 提取周几(1=周日,7=周六,和DAYOFWEEK一致) .values('week_day') # 按周几分组 .annotate( group_revenue=Sum('revenue'), total_revenue=total_revenue_subq ) .annotate(revenue_share=F('group_revenue') / F('total_revenue')) # 计算占比 .values('week_day', 'revenue_share') # 保留需要的字段 .order_by('week_day') )
解法2:正确使用Window函数(贴近原始SQL)
如果你用的是Django 2.0+且MariaDB版本≥10.2(支持窗口函数),可以用这种更贴近原始SQL的写法:
from django.db.models import Window, Sum, F, ExtractIsoWeekDay share = ( Orders.objects .annotate(week_day=ExtractIsoWeekDay('date')) .values('week_day') .annotate(group_revenue=Sum('revenue')) # 先分组计算每组营收 .annotate( # 窗口函数计算所有分组的营收总和(即总营收),partition_by为空表示整个结果集 total_revenue=Window(Sum('group_revenue'), partition_by=[]) ) .annotate(revenue_share=F('group_revenue') / F('total_revenue')) .values('week_day', 'revenue_share') .order_by('week_day') )
解法3:修正RawSQL写法(严格匹配原始SQL)
如果你需要完全复用原始SQL的逻辑,可以修正RawSQL的写法,确保触发GROUP BY:
from django.db.models import RawSQL, ExtractIsoWeekDay share = ( Orders.objects .annotate(week_day=ExtractIsoWeekDay('date')) .values('week_day') # 触发GROUP BY .annotate( revenue_share=RawSQL( 'SUM(revenue) / SUM(SUM(revenue)) OVER ()', [] # 无占位符,传空列表 ) ) .order_by('week_day') )
注意事项
ExtractIsoWeekDay返回的是1(周日)到7(周六),和MariaDB的DAYOFWEEK函数行为一致,无需额外调整;- 如果总营收为0,需要处理除以0的异常,可以加个条件判断或者用
NullIf函数; - 优先推荐解法1或2,RawSQL可读性差且不利于跨数据库迁移。
内容的提问来源于stack exchange,提问作者ZenCoding
相关产品推荐
相关产品推荐

