使用子查询,group_by和Left连接计数

时间:2016-04-25 16:08:10

标签: sql postgresql count subquery

我对这个特定的查询一直在争论。我正在制作一个排行榜'已向其指南添加或收到最多位置的用户。

我的数据模型如下:

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

用户可以向他/她的指南添加地点(通过提示)。该用户还可以从其他用户接收他/她的指南的地点(提示)。可以接受这些提示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

此查询会返回计数,但不会收到有关的提示,并且还会向其他用户计算给定的提示。我有一种预感,我需要使用子查询,首先从给定用户中选择所有指南ID,然后再简单地选择'选择guide_id = selected_guide_idstips.status = 1所有提示的计数。最后按users.blogger = 1

对结果进行分组

但我怎么写这个?

编辑1:

我已使用其他Guest表格更新了原始问题(这就是我使用owner_type and owner_id instead table_id的原因。我已经使用博客更新了用户表(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

然而,这将首先返回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

2 个答案:

答案 0 :(得分:1)

现在设置架构的方式,无法确定哪个指南属于哪个用户。

假设有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

答案 1 :(得分:1)

似乎添加/建议一个地方并不重要。一旦被接受(状态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;