Python:2.7版本:Django 1.11
你好,
我在Django查询中与COUNT DISTINCT一起使用条件聚合时遇到问题。问题是当我加入一个单独的表时,我对ID的不同计数似乎不起作用。我有一个查询,在该查询中,我会根据其他属性进行条件汇总以计算天数和总分钟数。
在下面的示例中,我们要同时查询两件事:
((请在示例中接受我。我尝试简化模型)
型号:
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=255)
class DailyLog(models.Model):
dog = models.ForeignKey(Dog, on_delete=models.CASCADE)
is_sunny = models.BooleanField(default=False)
class WalkSession(models.Model):
daily_log = models.ForeignKey(DailyLog, on_delete=models.CASCADE)
minutes_walked = models.IntegerField()
通过迁移填充数据:
d1 = Dog.objects.create(name="Fido")
d2 = Dog.objects.create(name="Fido2")
d3 = Dog.objects.create(name="Fido3")
dl1 = DailyLog.objects.create(dog=d1, is_sunny=True)
dl2 = DailyLog.objects.create(dog=d2, is_sunny=False)
dl3 = DailyLog.objects.create(dog=d3, is_sunny=False)
WalkSession.objects.create(daily_log=dl1, minutes_walked=100)
WalkSession.objects.create(daily_log=dl1, minutes_walked=200)
WalkSession.objects.create(daily_log=dl2, minutes_walked=50)
WalkSession.objects.create(daily_log=dl3, minutes_walked=999)
Python控制台:
简单检查分钟总数。
DailyLog.objects.all().values('dog__name').annotate(total_minutes_walked=Sum('walksession__minutes_walked'))
Result: <QuerySet [{'dog__name': 'Fido', 'total_minutes_walked': 300},
{'dog__name': 'Fido2', 'total_minutes_walked': 50},
{'dog__name': 'Fido3', 'total_minutes_walked': 999}]>
简单检查记录的晴天数。
DailyLog.objects.all().values('dog__name').annotate(sunny_days_logged=Count(Case(When(is_sunny=True, then='id'), distinct=True)))
Result: <QuerySet [{'dog__name': 'Fido', 'sunny_days_logged': 1},
{'dog__name': 'Fido2', 'sunny_days_logged': 0},
{'dog__name': 'Fido3', 'sunny_days_logged': 0}]>
通过条件聚合将DailyLog表和WalkSession连接起来的查询。
我们现在看到记录的晴天是'2'。我们期望它为'1'。
DailyLog.objects.all().values('dog__name').annotate(total_minutes_walked=Sum('walksession__minutes_walked'), sunny_days_logged=Count(Case(When(is_sunny=True, then='id'), distinct=True)))
Result: <QuerySet [{'dog__name': 'Fido', 'total_minutes_walked': 300, 'sunny_days_logged': 2},
{'dog__name': 'Fido2', 'total_minutes_walked': 50, 'sunny_days_logged': 0},
{'dog__name': 'Fido3', 'total_minutes_walked': 999, 'sunny_days_logged': 0}]>
我查看了所生成的查询,当我们使用CASE WHEN时,似乎DISTINCT选项被删除了。
SELECT dogwalker_dog.name,
SUM(dogwalker_walksession.minutes_walked) AS 'total_minutes_walked',
COUNT(CASE
WHEN dogwalker_dailylog.is_sunny = true THEN dogwalker_dailylog.id ELSE NULL END) AS 'sunny_days_logged'
FROM dogwalker_dailylog
INNER JOIN dogwalker_dog
ON dogwalker_dailylog.dog_id = dogwalker_dog.id
LEFT OUTER JOIN dogwalker_walksession
ON dogwalker_dailylog.id = dogwalker_walksession.daily_log_id
GROUP BY dogwalker_dog.name
文档确实说多次聚合可能显示错误的结果。
参考:https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#combining-multiple-aggregations我试图使用DISTINCT参数来解决此问题。
我在括号中的错误和缺少选项output_field选项。
下面的语句为每只狗提供了正确的晴天计数。
DailyLog.objects.all().values('dog__name').annotate(total_minutes_walked=Sum('walksession__minutes_walked'), sunny_days_logged=Count(Case(When(is_sunny=True, then='id'), output_field=IntegerField()), distinct=True))