使用子查询计数,group_by 和左连接
Count with subquery, group_by and Left join
我一直在为这个特定的查询而苦苦挣扎。我正在制作一个 'leaderboard' 的用户,这些用户在他们的指南中添加或收到最多的地方。
我的数据模型如下:
Users
uuid id
string first_name
bool blogger
Guests
uuid id
Tips (join model)
uuid id
uuid guide_id
uuid place_id
integer status
uuid owner_id
string owner_type
Guides
uuid id
uuid user_id
string name
Place
uuid id
string name
用户可以向 his/her 指南添加地点(通过提示)。同一用户还可以从其他用户那里接收到 his/her 指南的地方(提示)。这些小费可以采纳tips.status = 1
.
我想要的是:
first_name 以及在所有指南中添加或接受提示的所有地点的数量,但不包括他们给按 users.blogger = 1
分组的其他用户的提示。
示例:
Guest = true
you 40
user1 30
user2 25
Guest = false
user3 20
user4 15
user5 5
这是我目前拥有的:
SELECT tips.owner_id, tips.owner_type, count(tips.owner_id) AS places_count
FROM "tips"
LEFT JOIN users on (owner_type ='User' AND users.id = owner_id)
GROUP BY "tips"."owner_id", "tips"."owner_type"
ORDER BY places_count DESC
LIMIT 16
此查询会 return 计数,但不会考虑收到的相关提示,它还会计算给其他用户的提示。我有一种预感,我需要使用子查询,首先 select 来自给定用户的所有指南 ID,其次 'simply' select 所有提示的计数,其中 guide_id = selected_guide_ids
和 tips.status = 1
。最后按 users.blogger = 1
对结果进行分组
但是我该怎么写呢?
编辑 1:
我已经用额外的 Guest
table 更新了我的原始问题(这就是为什么我使用 table_id
的 owner_type and owner_id instead
。我已经更新了用户 table 与我想对结果进行分组的博主 (bool)。
示例数据:
Users
id first_name blogger
user1 Daniel true
user2 Quassnoi false
user3 vkp true
Guests
id
guest_1
guest_2
Guides
id user_id name
guide_1 user_1 Bugers
guide_2 user_1 Cool places
guide_3 user_2 Amsterdam
Tips
id guide_id place_id status owner_id owner_type
tip1 guide_1 place_1 1 user_1 User # user_1 added place_1 to his own guide guide_1 (accepted)
tip2 guide_1 place_2 1 guest_1 Guest # guest_1 suggested place_2 to user_1's guide guide_1 (accepted)
tip2 guide_1 place_2 0 guest_1 Guest # guest_1 suggested place_2 to user_1's guide guide_1 (rejected)
tip_3 guide_2 place_1 1 user_2 User # user_2 added place_1 to his own guide guide_3 (accepted)
tip_4 guide_2 place_2 1 user_2 User # user_2 added place_2 to his own guide guide_3 (accepted)
tip_5 guide_2 place_3 1 user_1 User # user_1 added place_3 to user_2's guide guide_2 (accepted)
Places
id name
place1 burgerbar
place2 burgermeester
place_3 bbq shack
我想要的结果是:
请注意,给其他用户的小费不计入小费提供者。
first_name tips_count blogger
Quassnoi 3 false (2 added by himself, 1 received from user_1)
Daniel 2 true (1 added by himself, 1 received from guest1. Note that the rejected tip does not count)
vkp 0 false
编辑 2
我稍微修改了 Quassnoi 的回答:
SELECT *
FROM users u
LEFT JOIN
(
SELECT g.user_id, COUNT(*) tips_count
FROM guides g
JOIN tips t
ON t.guide_id = g.id
AND (t.owner_id = g.user_id AND t.status = 1)
GROUP BY g.user_id
) g
ON g.user_id = u.id
ORDER BY tips_count DESC
然而,这 return 是所有 tips_count 首先为 NULL 的记录。我希望它们为 0 而不是 NULL。如何将 NULL tips_count 转换为 0?
编辑 3:
我更新了查询,以便它只计算 guide_id 等于给定用户的指南 ID 的提示。
SELECT *
FROM users u
LEFT JOIN
(
SELECT g.user_id, COUNT(*) tips_count
FROM guides g
JOIN tips t
ON t.guide_id = g.id
AND (t.guide_id = g.id AND t.status = 1)
GROUP BY g.user_id
) g
ON g.user_id = u.id
ORDER BY tips_count DESC
您现在的模式设置方式,无法分辨哪个指南属于哪个用户。
假设有一个 guide.owner
你忘记提及(或忘记添加),它将是:
SELECT *
FROM user u
LEFT JOIN
(
SELECT g.owner, COUNT(*) cnt
guide g
JOIN tips t
ON t.guide_id = g.id
AND (t.owner_id = g.owner OR t.status = 1)
GROUP BY
g.owner
) g
ON g.owner = u.id
看来谁added/suggested一个地方真的不重要。一旦它被接受(状态 1),它就属于指南,因此属于指南的用户。因此:
select u.first_name, u.blogger, count(t.id)
from users u
left join guides g on g.user_id = u.id
left join tips t on t.guide_id = g.id and t.status = 1
group by u.id
order by count(t.id) desc;
我一直在为这个特定的查询而苦苦挣扎。我正在制作一个 'leaderboard' 的用户,这些用户在他们的指南中添加或收到最多的地方。
我的数据模型如下:
Users
uuid id
string first_name
bool blogger
Guests
uuid id
Tips (join model)
uuid id
uuid guide_id
uuid place_id
integer status
uuid owner_id
string owner_type
Guides
uuid id
uuid user_id
string name
Place
uuid id
string name
用户可以向 his/her 指南添加地点(通过提示)。同一用户还可以从其他用户那里接收到 his/her 指南的地方(提示)。这些小费可以采纳tips.status = 1
.
我想要的是:
first_name 以及在所有指南中添加或接受提示的所有地点的数量,但不包括他们给按 users.blogger = 1
分组的其他用户的提示。
示例:
Guest = true
you 40
user1 30
user2 25
Guest = false
user3 20
user4 15
user5 5
这是我目前拥有的:
SELECT tips.owner_id, tips.owner_type, count(tips.owner_id) AS places_count
FROM "tips"
LEFT JOIN users on (owner_type ='User' AND users.id = owner_id)
GROUP BY "tips"."owner_id", "tips"."owner_type"
ORDER BY places_count DESC
LIMIT 16
此查询会 return 计数,但不会考虑收到的相关提示,它还会计算给其他用户的提示。我有一种预感,我需要使用子查询,首先 select 来自给定用户的所有指南 ID,其次 'simply' select 所有提示的计数,其中 guide_id = selected_guide_ids
和 tips.status = 1
。最后按 users.blogger = 1
但是我该怎么写呢?
编辑 1:
我已经用额外的 Guest
table 更新了我的原始问题(这就是为什么我使用 table_id
的 owner_type and owner_id instead
。我已经更新了用户 table 与我想对结果进行分组的博主 (bool)。
示例数据:
Users
id first_name blogger
user1 Daniel true
user2 Quassnoi false
user3 vkp true
Guests
id
guest_1
guest_2
Guides
id user_id name
guide_1 user_1 Bugers
guide_2 user_1 Cool places
guide_3 user_2 Amsterdam
Tips
id guide_id place_id status owner_id owner_type
tip1 guide_1 place_1 1 user_1 User # user_1 added place_1 to his own guide guide_1 (accepted)
tip2 guide_1 place_2 1 guest_1 Guest # guest_1 suggested place_2 to user_1's guide guide_1 (accepted)
tip2 guide_1 place_2 0 guest_1 Guest # guest_1 suggested place_2 to user_1's guide guide_1 (rejected)
tip_3 guide_2 place_1 1 user_2 User # user_2 added place_1 to his own guide guide_3 (accepted)
tip_4 guide_2 place_2 1 user_2 User # user_2 added place_2 to his own guide guide_3 (accepted)
tip_5 guide_2 place_3 1 user_1 User # user_1 added place_3 to user_2's guide guide_2 (accepted)
Places
id name
place1 burgerbar
place2 burgermeester
place_3 bbq shack
我想要的结果是:
请注意,给其他用户的小费不计入小费提供者。
first_name tips_count blogger
Quassnoi 3 false (2 added by himself, 1 received from user_1)
Daniel 2 true (1 added by himself, 1 received from guest1. Note that the rejected tip does not count)
vkp 0 false
编辑 2
我稍微修改了 Quassnoi 的回答:
SELECT *
FROM users u
LEFT JOIN
(
SELECT g.user_id, COUNT(*) tips_count
FROM guides g
JOIN tips t
ON t.guide_id = g.id
AND (t.owner_id = g.user_id AND t.status = 1)
GROUP BY g.user_id
) g
ON g.user_id = u.id
ORDER BY tips_count DESC
然而,这 return 是所有 tips_count 首先为 NULL 的记录。我希望它们为 0 而不是 NULL。如何将 NULL tips_count 转换为 0?
编辑 3:
我更新了查询,以便它只计算 guide_id 等于给定用户的指南 ID 的提示。
SELECT *
FROM users u
LEFT JOIN
(
SELECT g.user_id, COUNT(*) tips_count
FROM guides g
JOIN tips t
ON t.guide_id = g.id
AND (t.guide_id = g.id AND t.status = 1)
GROUP BY g.user_id
) g
ON g.user_id = u.id
ORDER BY tips_count DESC
您现在的模式设置方式,无法分辨哪个指南属于哪个用户。
假设有一个 guide.owner
你忘记提及(或忘记添加),它将是:
SELECT *
FROM user u
LEFT JOIN
(
SELECT g.owner, COUNT(*) cnt
guide g
JOIN tips t
ON t.guide_id = g.id
AND (t.owner_id = g.owner OR t.status = 1)
GROUP BY
g.owner
) g
ON g.owner = u.id
看来谁added/suggested一个地方真的不重要。一旦它被接受(状态 1),它就属于指南,因此属于指南的用户。因此:
select u.first_name, u.blogger, count(t.id)
from users u
left join guides g on g.user_id = u.id
left join tips t on t.guide_id = g.id and t.status = 1
group by u.id
order by count(t.id) desc;