我在MySql中有一个查询,我需要将其翻译成Django ORM。它涉及连接两个表,其中一个表有两个计数。我在Django中非常接近它,但我得到了重复的结果。这是查询:
SELECT au.id,
au.username,
COALESCE(orders_ct, 0) AS orders_ct,
COALESCE(clean_ct, 0) AS clean_ct,
COALESCE(wash_ct, 0) AS wash_ct
FROM auth_user AS au
LEFT OUTER JOIN
( SELECT user_id,
Count(*) AS orders_ct
FROM `order`
GROUP BY user_id
) AS o
ON au.id = o.user_id
LEFT OUTER JOIN
( SELECT user_id,
Count(CASE WHEN service = 'clean' THEN 1
END) AS clean_ct,
Count(CASE WHEN service = 'wash' THEN 1
END) AS wash_ct
FROM job
GROUP BY user_id
) AS j
ON au.id = j.user_id
ORDER BY au.id DESC
LIMIT 100 ;
我当前的Django查询(带回不需要的重复项):
User.objects.annotate(
orders_ct = Count( 'orders', distinct = True )
).annotate(
clean_ct = Count( Case(
When( job__service__exact = 'clean', then = 1 )
) )
).annotate(
wash_ct = Count( Case(
When( job__service__exact = 'wash', then = 1 )
) )
)
上面的Django代码生成以下查询,该查询很接近但不正确:
SELECT DISTINCT `auth_user`.`id`,
`auth_user`.`username`,
Count(DISTINCT `order`.`id`) AS `orders_ct`,
Count(CASE
WHEN `job`.`service` = 'clean' THEN 1
ELSE NULL
end) AS `clean_ct`,
Count(CASE
WHEN `job`.`service` = 'wash' THEN 1
ELSE NULL
end) AS `wash_ct`
FROM `auth_user`
LEFT OUTER JOIN `order`
ON ( `auth_user`.`id` = `order`.`user_id` )
LEFT OUTER JOIN `job`
ON ( `auth_user`.`id` = `job`.`user_id` )
GROUP BY `auth_user`.`id`
ORDER BY `auth_user`.`id` DESC
LIMIT 100
我可以通过做一些raw sql subqueries来实现它,但我希望尽可能保持抽象。
答案 0 :(得分:0)
我认为这样可行,链接的作业注释可能会产生重复的用户。
如果没有,你可以详细说明你看到的副本。
User.objects.annotate(
orders_ct = Count( 'orders', distinct = True )
).annotate(
clean_ct = Count( Case(
When( job__service__exact = 'clean', then = 1 )
) ),
wash_ct = Count( Case(
When( job__service__exact = 'wash', then = 1 )
) )
)
答案 1 :(得分:0)
基于this answer,您可以写:
User.objects.annotate(
orders_ct = Count( 'orders', distinct = True ),
clean_ct = Count( Case(
When( job__service__exact = 'clean', then = F('job__pk') )
), distinct = True ),
wash_ct = Count( Case(
When( job__service__exact = 'wash', then = F('job__pk') )
), distinct = True )
)
表格(加入后):
user.id order.id job.id job.service your case/when my case/when
1 1 1 wash 1 1
1 1 2 wash 1 2
1 1 3 clean NULL NULL
1 1 4 other NULL NULL
1 2 1 wash 1 1
1 2 2 wash 1 2
1 2 3 clean NULL NULL
1 2 4 other NULL NULL
wash_ct
的所需输出为2.在my case/when
中计算不同的值,我们将获得2.
答案 2 :(得分:0)
尝试添加values()
,distinct=True
combine Count()
's in one annotation()
{。}}。
Users.objects.values("id").annotate(
orders_ct = Count('orders', distinct = True)
).annotate(
clean_ct = Count(Case(When(job__service__exact='clean', then=1)),
distinct = True),
wash_ct = Count(Case(When(job__service__exact='wash',then=1)),
distinct = True)
).values("id", "username", "orders_ct", "clean_ct", "wash_сt")
使用values("id")
应为注释添加GROUP BY 'id'
,从而防止出现重复,请参阅docs。
此外,还有Coalesce
,但看起来并不需要,因为Count()
无论如何都会返回int
。 distinct
,distinct
Count()
中的Case
就足够了。
不确定Count()
是否需要<div id="parent">
Text text text text text
text text text text text
text text text text text
<div id="child"></div> //100px from top
Text text text text text
text text text text text
text text text text text
<div id="child"></div> //200px from top
Text text text text text
text text text text text
text text text text text
</div>
,因为无论如何都应该计算它们。