Python: 2.7 Версия: Django 1.11
Здравствуйте,
У меня проблемы с использованием условного агрегирования с COUNT DISTINCT в моем запросе Django. Проблема в том, что, когда я присоединяюсь к отдельной таблице, мой подсчет идентификаторов не работает. У меня есть запрос, в котором я делаю условное агрегирование для подсчета дней и суммы минут на основе других атрибутов.
В приведенном ниже примере мы хотим запросить две вещи одновременно:
- Количество «зарегистрированных солнечных дней» для каждой собаки.
- Общее количество времени, которое мы гуляли с каждой собакой
(Пожалуйста, потерпите меня на примере Я пытался упростить модели)
Модели:
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}]>
Я посмотрел на сгенерированные запросы, и кажется, что опция DISTINCT пропускается при использовании CASE WHEN.
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, Иначе NULL END) AS 'sunny_days_logged'
- Почему DISTINCT сбрасывается при использовании CASE WHEN?
- Было бы лучше разделить запросы, а не пытаться вычислить несколько вещей в одном запросе?