python - 在一个查询中对来自不同表的数值求和
问题描述
在 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()
如果返回的计数很小,这很好用,但如果数据库必须在内存中保存很多行来计算它们,这似乎很糟糕。
解决方案
您的解决方案只能通过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)
(或者通过外部引用,如果它可以工作),但查询计划可能更糟。
另一个问题是 aSELECT
没有表是不可能的。因此,我将在查询的基础上使用不重要表的不重要行。
例子:
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 docs 确认不存在简单的解决方案。
在子查询表达式中使用聚合
...
...这是在子查询中执行聚合的唯一方法,因为使用 aggregate() 尝试评估查询集(如果有 OuterRef,这将无法解决)。
推荐阅读
- c# - SSRS 从 Oracle 服务器检索 BLOB 到 SSRS 报告中的文本
- android - 为什么未检测到前置摄像头(CAMERA_FACING_FRONT)?
- java - Java:匹配正则表达式,除非以任意后缀结尾
- nginx - Nginx 错误日志没有列出 404s
- powershell - 从已经具有一系列值的数组中填充属性值 - PowerShell
- android - 当键盘在三星平板电脑中启动时,滚动视图不会滚动到结束
- r - 通过 R 中的 SCP 发送文件
- javascript - scrollview insde flatlist 不滚动
- c# - 最初对 acctName 上的销售订单客户查找进行排序
- variables - GNU Make,来自多个先决条件行的 `$<` 的值