使用具有多个条件聚合的DISTINCT(注释)

问题描述 投票:1回答:1

Python:2.7版本:Django 1.11

你好,

我在Django查询中与COUNT DISTINCT一起使用条件聚合时遇到问题。问题是当我加入一个单独的表时,我对ID的不同计数似乎不起作用。我有一个查询,在该查询中,我会根据其他属性进行条件汇总以计算天数和总分钟数。

在下面的示例中,我们要同时查询两件事:

  • 每只狗的“记录的晴天数”。
  • 我们ed狗的总时间

((请在示例中接受我。我尝试简化模型)

型号:

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
  • DISTINCT缺少COUNT个。
  • COUNT(DISTINCT大小写当dogwalker_dailylog.is_sunny = true时,dogwalker_dailylog.id否则为空END)AS'sunny_days_logged'

文档确实说多次聚合可能显示错误的结果。

参考:https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#combining-multiple-aggregations我试图使用DISTINCT参数来解决此问题。

  • 为什么在使用CASE WHEN时会丢弃DISTINCT?
  • 最好将查询分开,而不是尝试在一个查询中计算多个事物吗?
python-2.7 distinct annotate django-1.11 conditional-aggregation
1个回答
0
投票

我在括号中的错误和缺少选项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))
© www.soinside.com 2019 - 2024. All rights reserved.