如何在 Django 中找到 Min(Sum(annotated column))

How to find Min(Sum(annotated column)) in Django

我有四个 tableA、B、C 和 D。每个 table 通过 id 列以 A -> B -> C -> D 的方式关联。 例如。 A.id = B.a_id、B.id = C.b_id 和 C.id = D.c_id

我正在努力实现这样的目标

SELECT x.id, min(x.total) as mintotal FROM (SELECT "A"."id",
SUM(("D"."amount" * "D"."quantity")) AS "total", "C"."id" AS "qid" 
FROM "A"  LEFT OUTER JOIN "B" ON ("A"."id" = "B"."a_id")  LEFT OUTER
JOIN "C" ON ("B"."id" = "C"."c_id")  LEFT OUTER JOIN "D" ON ("C"."id"
= "D"."c_id")  GROUP BY "A"."id", "C"."id")  as x group by x.id  ORDER BY mintotal ASC

我的等效 django 代码

query1 = (
    A.objects.all().annotate(
        qid=models.F('b__c__id'),
        total=Sum(models.ExpressionWrapper(
            models.F('b__c__d__amount')*models.F('b__c__d__quantity'),
            output_field=models.DecimalField()
        ))
    ).order_by('total')
)

它给了我内部查询输出,但是当我再次尝试 select id 和 Min(total) 时它抛出错误 -

FieldError: Cannot compute Min('total'): 'total' is an aggregate

我是 Django 的新手,我不确定如何使用子查询或 exists 来获得这个结果。任何帮助将不胜感激

看起来这个SQL相当于你想要的

SELECT
    A.id,
    (
      SELECT
          Sum(D.amount * D.quantity)
      FROM
          D
      JOIN
          C ON C.id = D.c_id
      JOIN
          B ON B.id = C.b_id
      WHERE
          B.a_id = A.id
      GROUP BY C.id
      ORDER BY Sum(D.amount * D.quantity) ASC
      LIMIT 1
        ) as mintotal
FROM
    A;

这可以使用 Django 的子查询来完成

from django.db.models import Subquery, OuterRef, F

subquery = Subquery(D.objects.values(c__id)
                             .annotate(total=Sum(F('amount') * F('quantity')))
                             .filter(c__b__a__id=OuterRef('id'))
                             .order_by('total')
                             .values('total')[:1])

query1 = A.objects.annotate(mintotal=subquery)
 
# And if you really just want the A.id and mintotal columns:
query1 = A.objects.annotate(mintotal=subquery).values('id', 'mintotal')