【问题标题】:use inner join on three table and aggregation in a single query在单个查询中对三个表和聚合使用内连接
【发布时间】:2016-02-05 21:44:01
【问题描述】:

我有三个模型,

class A(models.Model):
    code=models.CharField(max_length=9,unique=True)

class B(models.Model):
    submitted_by = models.ForeignKey(D)
    a = models.OneToOneField(A)
    name = models.CharField(max_length=70,blank=True,default='')


class C(models.Model):
    status = models.PositiveSmallIntegerField()
    status_time = models.DateTimeField(auto_now_add=True)
    a = models.ForeignKey(A)

我需要查询,以便我可以获得代码(来自模型 A)、名称(来自模型 B)和状态时间(来自模型 C)和状态(来自模型 C),其中提交的_by_id=1 和状态应该是最大值每个id。

sql 是:

SELECT A.code ,B.name,C.status,C.status_time FROM `A`  INNER JOIN  `B`  on A.id=B.a_id INNER JOIN  `C`  on A.id=C.a_id where B.submitted_by_id=1 and C.status_time=(se lect max(C.status_time) from `C` pipeline where C.a_id=A.id)

如果有人可以帮助我处理 django ORM。 我无法理解如何在单个查询中同时使用内部联接、聚合和子查询。

编辑:

B.objects.filter(submitted_by_id=1).values('name','a__code','a__c__status_time','a__c__status').order_by('-a__c__status').first()

我试过这个查询。但它只返回一行,即具有最大状态的行。 我们可以修改它并返回每个 id 的结果吗?

【问题讨论】:

  • 仍在寻找答案。我需要这个查询来创建一个数据表视图。

标签: python sql django django-orm


【解决方案1】:

您不会像 SQL 那样使用 Django ORM。如果我在 Django ORM 中正确理解您,您的查询将如下所示:

result = []
bs = B.objects.filter(submitted_by_id=1)
for b in bs:
    a = b.a
    c = C.objects.filter(a=a).order_by('-status').first()
    result.append([a.code, b.name, c.status, c.status_time])

【讨论】:

  • 谢谢。有用。但我需要在单个查询中执行此操作。我已经尝试过 sql,它工作正常。即使你的答案是完美的。但是,如果你能帮助我在一个查询中做到这一点。如果不可能,请解释原因
  • 不幸的是这是不可能的,因为在 Django ORM 中你不能 JOIN 不同的模型。但是,您可以使用 connection 对象并执行原始的 SQL 查询。这是文档的链接:docs.djangoproject.com/en/1.8/topics/db/sql/…
  • 我通过编辑更新了我的问题。可能是如果您可以解决,否则我会接受您的回答并继续前进。如果您可以为此提供有关原始 SQL 的建议会更好。
  • 我不能保证,但你可以试试:[[obj[0], obj[1], max(obj[2]), obj[3][obj[2].index(max(obj[2]))]] for obj in B.objects.filter(submitted_by_id=1).values('name','a__code','a__c__status_time','a__c__status').order_by('-a__c__status')]
  • 你的键名是什么?他们是'name''a__code''a__c__status_time''a__c__status'
【解决方案2】:

也许以下可以帮助:

results = []
b_set = B.objects.filter(submitted_by__id=1)
for b in b_set:
    c = C.objects.filter(a__b=b).order_by('-status_time').first()
    results.append([c.a.code, c.a.b.name, c.status, c.status_time])

【讨论】:

  • 我想在单个查询中执行此操作。
【解决方案3】:

您或许可以使用annotationselect_related() 来做您想做的事。

我根本没有测试过,但这是我会尝试的:

from django.db.models import F
from django.db.models import Max

annotated_c = C.objects.annotate(last_status_time=Max('a__cs__status_time'))
last_c = annotated_c.filter(status_time=F('last_status_time'),
                            a__b__submitted_by_id=1)

for c in last_c.select_related('a', 'a__b'):
    print c.a.code, c.a.b.name, c.status_time

您可能需要将related_name 添加到外键中。

django.db 记录器设置为DEBUG 级别,以查看您正在生成的SQL。

【讨论】:

  • 还有一个条件是他想过滤“submitted_by_id”=1。也许你也可以添加这个。
  • 感谢@FullOfQuestions,我现在添加了缺少的过滤器。
猜你喜欢
  • 2021-08-18
  • 1970-01-01
  • 2021-07-16
  • 2023-04-06
  • 2014-03-29
  • 1970-01-01
  • 2012-11-18
  • 2021-07-03
  • 2021-12-19
相关资源
最近更新 更多