Aze*_*zee 2 python django postgresql orm aggregate
为了简单起见,我有四个表(A、B、Category 和 Relation),Relation 表将Intensity
A 的 A存储在 B 中,Category 存储 B 的类型。
A <--- 关系 ---> B ---> 类别
(所以A和B的关系是n比n,当B和Category的关系是n比1时)
我的类别和需要一个ORM到组关系的记录,然后计算出Sum
的Intensity
每个(A类,A)(似乎简单到这里),然后我要诠释的最大计算Sum
每个类别。
我的代码是这样的:
A.objects.values('B_id').annotate(AcSum=Sum(Intensity)).annotate(Max(AcSum))
Run Code Online (Sandbox Code Playgroud)
哪个抛出错误:
django.core.exceptions.FieldError: Cannot compute Max('AcSum'): 'AcSum' is an aggregate
Run Code Online (Sandbox Code Playgroud)
具有相同错误的Django-group-by包。
有关更多信息,请参阅此 stackoverflow 问题。
我正在使用 Django 2 和 PostgreSQL。
有没有办法使用 ORM 来实现这一点,如果没有,使用原始 SQL 表达式的解决方案是什么?
经过一番挣扎,我发现我写的确实是一个聚合,但是我想要的是找出每个类别中每个A的AcSum的最大值。所以我想我必须在 AcSum Calculation 之后再次对结果进行分组。基于这种见解,我发现了一个堆栈溢出问题,它提出了相同的概念(这个问题是在 1 年,2 个月前提出的,没有任何公认的答案)。将另一个值('id')链接到集合既不能作为 group_by 也不能作为输出属性的过滤器,它会从集合中删除 AcSum。由于按结果集分组的变化,将 AcSum 添加到 values() 也不是一个选项。我想我想做的是根据列内的字段(即id)重新分组查询分组。有什么想法吗?
小智 5
你不能做一个聚合的聚合Max(Sum())
,它在 SQL 中是无效的,无论你是否使用 ORM。相反,您必须将表与自身连接以找到最大值。您可以使用子查询执行此操作。下面的代码对我来说看起来很正确,但请记住,我没有什么可以运行它,所以它可能并不完美。
from django.db.models import Subquery, OuterRef
annotation = {
'AcSum': Sum('intensity')
}
# The basic query is on Relation grouped by A and Category, annotated
# with the Sum of intensity
query = Relation.objects.values('a', 'b__category').annotate(**annotation)
# The subquery is joined to the outerquery on the Category
sub_filter = Q(b__category=OuterRef('b__category'))
# The subquery is grouped by A and Category and annotated with the Sum
# of intensity, which is then ordered descending so that when a LIMIT 1
# is applied, you get the Max.
subquery = Relation.objects.filter(sub_filter).values(
'a', 'b__category').annotate(**annotation).order_by(
'-AcSum').values('AcSum')[:1]
query = query.annotate(max_intensity=Subquery(subquery))
Run Code Online (Sandbox Code Playgroud)
这应该生成如下 SQL:
SELECT a_id, category_id,
(SELECT SUM(U0.intensity) AS AcSum
FROM RELATION U0
JOIN B U1 on U0.b_id = U1.id
WHERE U1.category_id = B.category_id
GROUP BY U0.a_id, U1.category_id
ORDER BY SUM(U0.intensity) DESC
LIMIT 1
) AS max_intensity
FROM Relation
JOIN B on Relation.b_id = B.id
GROUP BY Relation.a_id, B.category_id
Run Code Online (Sandbox Code Playgroud)
Subquery
通过使用后端特定功能array_agg
(如(Postgres) 或GroupConcat
(MySQL))来收集Relation.ids
在外部查询中组合在一起的数据,消除加入的性能可能会更高。但我不知道你用的是什么后端。