使用多个Sum时,错误的大数字,在注释中使用Count聚合

时间:2015-11-11 11:37:09

标签: django django-models django-orm

我有这些模特:

User:
    email = EmailField()

Payment:
    user = ForeignKey(User)
    sum = DecimalField()

GuestAccount:
    user = ForeignKey(User)
    guest = ForeignKey(User)

我想收到用户的电子邮件,来自每个用户的金额 和客人帐号。

我的查询:

User.objects.annotate(
    money=Sum('payment__sum'),
    guests_number=Count('guestaccount')
).values('email', 'money', 'guests_number')

但是查询结果中的moneyguests_number大于实际值:

{'guests_number': 0,  'email': 'a@b.cd',            'money': None}
{'guests_number': 20, 'email': 'user1@mail.com',    'money': Decimal('6600.00')}
{'guests_number': 4,  'email': 'user1000@test.com', 'money': Decimal('2500.00')}
{'guests_number': 0,  'email': 'zzzz@bbbbb.com',    'money': None}

如果我将查询分成两个单独的查询,我注意到我得到了正确的数据:

User.objects.annotate(money=Sum('payment__sum')).values('email', 'money')
User.objects.annotate(guests_number=Count('guestaccount')).values('email', 'guests_number')

上半场的正确结果:

{'email': 'a@b.cd',            'money': None}
{'email': 'user1@mail.com',    'money': Decimal('1650.00')}
{'email': 'user1000@test.com', 'money': Decimal('1250.00')}
{'email': 'zzzz@bbbbb.com',    'money': None}

下半场的正确结果:

{'email': 'a@b.cd',            'guests_number': 0}
{'email': 'user1@mail.com',    'guests_number': 4}
{'email': 'user1000@test.com', 'guests_number': 2}
{'email': 'zzzz@bbbbb.com',    'guests_number': 0}

另外,我注意到我可以在distinct=True聚合中添加Count

User.objects.annotate(
    money=Sum('payment__sum'),
    guests_number=Count('guestaccount', distinct=True)
).values('email', 'money', 'guests_number')

它修复了guests_number

{'guests_number': 0, 'email': 'a@b.cd',            'money': None}
{'guests_number': 4, 'email': 'user1@mail.com',    'money': Decimal('6600.00')}
{'guests_number': 2, 'email': 'user1000@test.com', 'money': Decimal('2500.00')}
{'guests_number': 0, 'email': 'zzzz@bbbbb.com',    'money': None}

不幸的是,distinct聚合中没有Sum参数。

我的查询有什么问题?如何通过注释中的每个聚合来修复这些数字变大?

1 个答案:

答案 0 :(得分:0)

原始SQL查询调查显示问题来自多个LEFT OUTER JOIN。所以我最终得到了原始的SQL:

User.objects.extra(select={
                "money": """
                    SELECT SUM("website_payment"."sum")
                    FROM "website_payment"
                    WHERE "website_user"."id" = "website_payment"."user_id"
                """,
                "guests_number": """
                    SELECT COUNT("guests_guestaccount"."id")
                    FROM "guests_guestaccount"
                    WHERE "website_user"."id" = "guests_guestaccount"."user_id"
                """,
            }
        ).values('email', 'money', 'guests_number')

但我需要将这些字段注释为查询对象,extra不要这样做。