【问题标题】:Postgres: join two queries and select based on resultPostgres:加入两个查询并根据结果进行选择
【发布时间】:2016-09-22 17:18:46
【问题描述】:

有一个社交网络,每个用户都可以在其中转发其他用户的帖子。您的帖子每转发 10 次,您将获得一份礼物。有两个表:giftsrepost_history,请参见下面的方案。

问题: 如何编写一个查询来计算我需要为系统中的每个用户赠送多少礼物?

=========
= gifts =
=========
   id       // PK
 user_id    // id of user which received a gift
 amount     // amount of gifts (bonuses), may be + or -
  type      // type of a gift.  The only type we're interested in is 'REPOST_TYPE'

==================
= repost_history =
==================
      id     // PK
    user_id  // id of a user which did repost
    owner_id // id of a user whose post was reposted

查询算法:

1) 查找每个用户的总转发数 SELECT owner_id, COUNT(owner_id) FROM repost_history GROUP BY owner_id;

2) 查找每个用户的REPOST_TYPE 礼物总数 SELECT user_id, COUNT(amount) FROM gifts WHERE type = 'REPOST_TYPE' GROUP BY user_id;

3) 基于owner_id = user_id 加入第一步和第二步

4) 基于第三步结果的 (user_id, gift_to_grand_count) 结果集。在哪里<gift_to_grand_count> = (<reposts_of_user> / 10) - <user_repost_gifts_amount>

我的解决方法: 1-3 步实现(不起作用,因为我不知道如何将子查询结果设置为变量)。如何使其工作并执行第 4 步?

(
  SELECT owner_id, COUNT(owner_id) AS reposts_count
  FROM reposts_history
  GROUP BY owner_id 
  AS user_reposts
)   
INNER JOIN (
  SELECT user_id, COUNT(amount) AS gifts_count
  FROM gifts 
  WHERE type = 'REPOST_GIFT' 
  GROUP BY user_id 
  AS user_gifts
) 
ON user_reposts.owner_id = user_gifts.user_id

数据样本:

为简单起见,假设我们希望在每 3 次转发(而不是每 10 次)时赠送一份礼物

gifts - 您可以看到 user_id=1 已获得 1 个 REPOST_TYPE 的礼物。我们对他花了多少礼物不感兴趣。

id | user_id | amount |     type      |
 1 |    1    |    1   | 'REPOST_TYPE' |
 2 |    1    |    2   | 'OTHER_TYPE'  |
 3 |    1    |   -1   | 'REPOST_TYPE' |
 4 |    2    |    1   | 'REPOST_TYPE' |

reposts_history - 您可以看到用户 owner_id=1 被其他用户转发了 6 次。

id  | user_id | owner_id | another columns...
 1  |    2    |    1     |
 2  |    3    |    1     |
 3  |    4    |    1     |
 4  |    5    |    1     |
 5  |    2    |    1     |
 6  |    6    |    1     |
 6  |   13    |    2     |

所以user_id=1 应该被授予<total_reposts> / 3 - <already_granted_gifts_amount> = 6 / 3 - 1 = 1 礼物。

我想为系统中的所有用户获取:

user_id | gifts_to_grant |
   1    |       1        |
   2    |       0        |
     ..........

【问题讨论】:

  • 请提供数据样本和预期结果
  • @sagi 请给我 5 分钟
  • @sagi 请检查我的数据样本
  • @ThrostenKettner 解决方案能解决您的问题吗?还是您还需要帮助?
  • @sagi 只需几分钟,需要了解它是如何工作的

标签: sql postgresql subquery inner-join


【解决方案1】:

您需要外部联接才能找到值得礼物但尚未收到礼物的用户:

select
  b.ownerid as userid, 
  b.rebets_count, 
  b.rebets_count / 10 as gifts_expected, 
  coalesce(g.gifts_count, 0) as gifts_received,
  b.rebets_count / 10 - coalesce(g.gifts_count, 0) as gifts_missing 
from
(
  select owner_id, count(*) as rebets_count
  from bets 
  group by owner_id 
) b  
left join 
(
  select user_id, count(*) as gifts_count
  from gifts 
  where type = 'REBET_GIFT' 
  group by user_id 
) g on g.user_id = b.owner_id;

【讨论】:

  • 刚刚提供的数据样本。请您检查一下您的查询
  • 如何只选择gifts_missing > 0的用户?
  • 用另一个选择包装并过滤它们@VolodymyrBakhmatiuk
  • @sagi 为什么我不能只做HAVING gifts_missing > 0
  • 您只需使用WHERE 子句:where b.rebets_count / 10 - coalesce(g.gifts_count, 0) > 0。您不能在HAVING 中使用别名,因为HAVING 子句SELECT 子句之前执行。
猜你喜欢
  • 1970-01-01
  • 2013-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-01
  • 1970-01-01
  • 2018-03-08
相关资源
最近更新 更多