具有标量值的Django子查询

时间:2016-06-24 20:58:46

标签: python mysql django database

是否可以使用Django ORM将子查询结果与标量值进行比较?我很难转换它:

SELECT payment_subscription.*
FROM payment_subscription payment_subscription
  JOIN payment_recurrent payment_recurrent ON payment_subscription.id = payment_recurrent.subscription_id
WHERE
  payment_subscription.status = 1
  AND (SELECT expiration_date
       FROM payment_transaction payment_transaction
       WHERE payment_transaction.company_id = payment_subscription.company_id
             AND payment_transaction.status IN ('OK', 'Complete')
       ORDER BY payment_transaction.expiration_date DESC, payment_transaction.id DESC
       LIMIT 1) <= ?

要点是:

  1. 子查询的标量值与任意参数的最后一次比较。
  2. 子查询与具有公司标识
  3. 的外部查询之间的连接

2 个答案:

答案 0 :(得分:1)

您可以(从Django 1.11开始)对子查询进行批注,然后对其进行切片以确保仅获得“第一”结果。然后,您可以通过比较所需的值来过滤该子查询注释。

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

expiration_date = Transaction.objects.filter(
    company=OuterRef('company'),
    status__in=['OK', 'Complete'],
).order_by('-expiration_date').values('expiration_date')[:1]

Subscription.objects.filter(status=1).annotate(
    expiration_date=Subquery(expiration_date),
).filter(expiration_date__lte=THE_DATE)

但是...

当前,这可能会导致非常糟糕的性能:您的数据库将对子查询进行两次评估(一次是在where子句中,通过过滤器,一次是在select子句中,通过注释)。目前正在解决该问题,但目前尚未完成。

答案 1 :(得分:0)

Subscription.objects.annotate(
    max_expiraton_date=Max('transaction__expiration_date')
).filter(
    status=1,
    recurrent__isnull=False,  # [inner] join with recurrent
    transaction__status__in=['OK', 'Complete'],
    max_expiraton_date=date_value
)

这会产生其他SQL查询,但会获得相同的Subscription个对象。