sql >> Base de Datos >  >> RDS >> PostgreSQL

¿Calcular Max of Sum de un campo anotado sobre una consulta agrupada en Django ORM?

No puede hacer un agregado de un agregado Max(Sum()) , no es válido en SQL, ya sea que esté usando el ORM o no. En su lugar, debe unir la tabla a sí misma para encontrar el máximo. Puedes hacer esto usando una subconsulta. El siguiente código me parece correcto, pero tenga en cuenta que no tengo algo para ejecutarlo, por lo que podría no ser perfecto.

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))

Esto debería generar SQL como:

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

Puede ser más eficaz eliminar la unión en Subquery mediante el uso de una función específica de back-end como array_agg (Postgres) o GroupConcat (MySQL) para recopilar Relation.ids que se agrupan en la consulta externa. Pero no sé qué backend estás usando.