【问题标题】:Sum numeric values from different tables in one query在一个查询中对来自不同表的数值求和
【发布时间】:2020-09-26 08:17:47
【问题描述】:

在 SQL 中,我可以将两个计数相加

SELECT (
  (SELECT count(*) FROM a WHERE val=42)
  +
  (SELECT count(*) FROM b WHERE val=42)
)

如何使用 Django ORM 执行此查询?

我得到的最接近的是

a.objects.filter(val=42).order_by().values_list('id', flat=True).union(
    b.objects.filter(val=42).order_by().values_list('id', flat=True)
).count()

如果返回的计数很小,这可以正常工作,但如果数据库必须在内存中保存很多行来计算它们,这似乎很糟糕。

【问题讨论】:

    标签: python django django-orm


    【解决方案1】:

    您的解决方案只能通过values('pk') 而不是values_list('id', flat=True) 稍微简化,因为这只会影响输出的一种类型,但是两个查询集的源 SQL 是相同的:

    SELECT id FROM a WHERE val=42 UNION SELECT id FROM b WHERE val=42
    

    .count() 方法只对子查询进行查询:

    SELECT COUNT(*) FROM (... subquery ...)
    

    数据库后端不必将所有值保存在内存中。它也只能数数而忘记。 (未检查)

    同样,如果你运行一个简单的SELECT COUNT(id) FROM a,它不需要收集id


    SELECT count(*) FROM a WHERE val=42 形式的子查询在更大的查询中是不可能的,因为 Django 不对聚合使用惰性求值并立即求值。

    评估可以推迟,例如通过按一些只有一个可能值的表达式进行分组,例如GROUP BY (i >= 0)(如果可行,也可以通过外部引用),但查询计划可能更糟。

    另一个问题是SELECT 在没有表格的情况下是不可能的。因此,我将在查询的基础上使用不重要表的不重要行。

    例子:

    qs = Unimportant.objects.filter(pk=unimportant_pk).values('id').annotate(
        total_a=a.objects.filter(val=42).order_by().values('val')
            .annotate(cnt=models.Count('*')).values('cnt'),
        total_b=b.objects.filter(val=42).order_by().values('val')
            .annotate(cnt=models.Count('*')).values('cnt')
    )
    

    这不是很好,但可以很容易地并行化

    SELECT
        id,
        (SELECT COUNT(*) AS cnt FROM a WHERE val=42 GROUP BY val) AS total_a,
        (SELECT COUNT(*) AS cnt FROM b WHERE val=42 GROUP BY val) AS total_b
    FROM unimportant WHERE id = unimportant_pk
    

    Django 文档确认不存在简单的解决方案。

    Using aggregates within a Subquery expression
    ...
    ...这是在子查询中执行聚合的唯一方法,因为使用 aggregate() 尝试评估查询集(如果存在 OuterRef,则无法解决)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 1970-01-01
      • 2014-09-02
      • 2021-10-08
      • 2015-06-23
      相关资源
      最近更新 更多