使用 Django 子查询作为 FROM 表或 CTE 以便在聚合上有一个窗口?

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

我正在尝试对组内的成本进行求和,然后在多个组上添加累积成本。简化版:

class Cost(Model):
    year = IntegerField()
    month = IntegerField()
    cost = DecimalField()
select 
  "year",
  "month",
  month_total,
  sum(month_total) over (
    partition by 1 order by "year", "month" rows between unbounded preceding and current row
  ) as cum_total
from (
  select "year", "month", sum("cost") as month_total
  from app_cost
  group by "year", "month"
) as innerq
order by "year", "month"

但我不知道如何用 Django 的 ORM 来编写它:

innerq = Cost.objects.values("year", "month").annotate(month_total=Sum("cost"))

一切都很好,但如果我这样做:

outerq = innerq.annotate(
    cum_total=Window(
        expression=Sum("month_total"),
        partition_by=[Value(1)],
        order_by=[F("year"), F("month")],
        frame=RowRange(None, 0),  # UNBOUNDED PRECEDING -> CURRENT ROW
    ),
)

我得到:

FieldError:无法计算 Sum('month_total'):'month_total' 是一个聚合

如何将查询集

innerq
强制放入子查询中,如上面的 SQL 所示? (我知道
Subquery
,我只是还没有找到在这里应用它的方法。)

django postgresql django-orm
1个回答
0
投票

我一直在为类似的问题而苦苦挣扎,刚刚发现了 django-cte 项目,该项目似乎证实了开箱即用的 ORM 没有所需的支持,并提供了一种使用其前进的方法With

使用它,我相信您的问题的简化版本可以通过以下方式解决:

from django_cte import With cte = With( Cost.objects .values("year", "month", "month_total") .annotate(month_total=Sum("cost")) ) innerq = cte.join(Cost, region=cte.col.year).with_cte(cte)...

(我的用例与你的有点不同)。请参阅
文档
了解更多信息。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.