【问题标题】:How to count on join a table with 2 conditions?如何指望加入具有 2 个条件的表?
【发布时间】:2021-11-27 05:28:52
【问题描述】:

我有一个items

id name
1 Nganu
2 Kae
3 Lho

我还有一个item_usages 表:

id item_id user_id usage_time
1 1 99 2021-10-07 00:00:00
2 2 99 2021-10-07 00:00:00
3 1 99 2021-10-08 00:00:00
4 1 22 2021-10-08 00:00:00
5 3 22 2021-10-08 00:00:00
6 1 99 2021-10-08 00:00:00

我想在查询中找到一个项目的总使用量和用户使用量。我想查找 user_id 99 用法的示例,预期结果:

id name total_usage user_usage
2 Kae 1 1
1 Nganu 4 3
3 Lho 1 0

我试过了:

select 
    "items".*,
    count(total_usage.id) as total_usage, 
    count(user_usage.id) as user_usage 
from 
    "items"
left join 
    "item_usages" as "total_usage" on "items"."id" = "total_usage"."item_id"
left join 
    "item_usages" as "user_usage" on "user_usage"."item_id" = "items"."id" 
                                  and "user_usage"."user_id" = 99
group by 
    "items"."id";

但它会返回:

id name total_usage user_usage
2 Kae 1 1
1 Nganu 12 12
3 Lho 1 0

item_usages 只有 6 行,为什么 Nganu 两种用法都有 12 行?如何修复我的查询?

我在 PostgreSQL 12.8 和 13.4 上试过,我也在 SQLFiddle(PostgreSQL 9.6) 上测试过,这里是链接:

http://sqlfiddle.com/#!17/f1aac/5

我得到了返回正确结果的查询:

select 
    "items".*,
    min(total_usage.total_count) as total_usage, 
    count(user_usage.id) as user_usage 
from "items"
left join 
    (select item_id,count(item_id) as total_count  from item_usages group by item_id) as total_usage 
     on "items"."id" = "total_usage"."item_id"
left join "item_usages" as "user_usage" 
     on "user_usage"."item_id" = "items"."id" and "user_usage"."user_id" = 99
 group by "items"."id";

但我不知道性能,所以如果可能的话我仍然会找到更快的查询并且仍然想知道:

为什么我的第一个查询给出了错误的结果?

【问题讨论】:

    标签: sql postgresql join count left-join


    【解决方案1】:

    您的查询返回高数字的原因是您加入了 2 次。

    (来自Nganu这边)第一次join会产生4行,第二次会将这4行映射到同一张表的3行,结果是12行。

    只需 1 个连接即可解决此问题:

    select "items".id, 
    count(total_usage.id) as total_usage, 
    sum(case when total_usage.user_id = 99 then 1 else 0 end) as user_usage
    from "items"
    left join "item_usages" as "total_usage" on "items"."id" = "total_usage"."item_id"
    group by "items".id
    

    而且它应该工作得更快(虽然,在一个小数据集上是不可见的)

    【讨论】:

    • 谢谢,但是如何结合查询,我尝试了having sum(case when total_usage.user_id = 99 then 1 else 0 end) < 2 但不起作用
    • 我在上次测试中打错字了,它使用有,并且比基于我的测试的查询更快。非常感谢。
    • 我建议将我的查询结果包装在第二个中,然后过滤,即“WHERE user_usage
    • 会比having快很多吗?如果不是,我仍然更喜欢使用have,因为我使用的是ORM,所以很难像你在ORM中提到的那样包装结果。
    • 在我看来完全没有,只是更容易阅读
    猜你喜欢
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    • 2015-10-05
    • 2019-09-03
    • 2013-10-03
    • 1970-01-01
    • 2020-11-10
    • 1970-01-01
    相关资源
    最近更新 更多