COUNT的PostgreSQL值乘以

时间:2017-03-07 20:05:33

标签: sql ruby-on-rails postgresql count

我是Rails开发人员,我是编写SQL脚本的新手。我有usersportfoliosviewsfavoritesendorsements表格。 users有许多portfoliosendorsements.投资组合has many次观看, many次收藏and many代言。

这是我写的脚本

top_users = User.find_by_sql(
  "SELECT users.*, 
    COUNT(portfolios.id) + 
    COUNT(views.id) + 
    COUNT(favorites.id) + 
    COUNT(case when endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id then 1 else 0 end) +
    COUNT(case when endorsements.user_id = users.id then 1 else 0 end)
    AS total 
  FROM users 
  LEFT OUTER JOIN portfolios ON portfolios.user_id = users.id 
  LEFT OUTER JOIN views ON views.subject_id = portfolios.id AND portfolios.user_id = users.id 
  LEFT OUTER JOIN favorites ON favorites.subject_id = portfolios.id AND portfolios.user_id = users.id 
  LEFT OUTER JOIN endorsements ON endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id OR endorsements.user_id = users.id 
  GROUP BY users.id 
  ORDER BY total DESC LIMIT 8"
)

total计数并不完全符合我的预期,因为每个portfolio50分,view2分,favorite为值10分,endorsement2分。

假设我们有3个用户

user | COUNT 1 | COUNT 2 | COUNT 3 | COUNT 4 | COUNT 5
-------------------------------------------------------
1     | 0       | 0       | 0       | 0       | 10
2     | 2       | 2       | 2       | 2       | 0
3     | 5       | 0       | 0       | 0       | 0

使用我的脚本,结果按user 1user 2,然后users 3的顺序排列。但是,根据积分系统,它应该按user 3user 2然后user 1的顺序出现,因为user 3总积分为250,{{1总计为users 2128user 1,这是我期望的顺序。我试过这个:

20

我尝试了上面的脚本,但对我不起作用。任何想法或帮助将不胜感激。同样,我对原始SQL脚本非常新。

已更新 当LEFT INNTER JOIN多表时,我最终这样做是为了避免重复计算问题。

top_users = User.find_by_sql(
  "SELECT users.*, 
    COUNT(portfolios.id) * 50 + 
    COUNT(views.id) * 2 + 
    COUNT(favorites.id) * 10 + 
    COUNT(case when endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id then 1 else 0 end) * 2 +
    COUNT(case when endorsements.user_id = users.id then 1 else 0 end) * 2
    AS total 
  FROM users 
  LEFT OUTER JOIN portfolios ON portfolios.user_id = users.id 
  LEFT OUTER JOIN views ON views.subject_id = portfolios.id AND portfolios.user_id = users.id 
  LEFT OUTER JOIN favorites ON favorites.subject_id = portfolios.id AND portfolios.user_id = users.id 
  LEFT OUTER JOIN endorsements ON endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id OR endorsements.user_id = users.id 
  GROUP BY users.id 
  ORDER BY total DESC LIMIT 8"
)

因为我不熟悉SQL脚本,因为我是一个非常初学者。上面更新的代码解决了我的问题,但我想知道如果我这样做,糟糕表现会如何。感谢您提供任何意见。

3 个答案:

答案 0 :(得分:1)

首先,除非你的'users'表只有一列,否则这会破坏以下规则:当你在select子句中有聚合函数时,每个未传递给聚合函数的列都必须在你的group by clause。

其次我不认为COUNT()函数中的case语句是有意义的。它们与您的加入中的语句相同。你应该能够计算endoresements.Id和Portfolios.id,我想。我可能会对你正在寻找的东西有点模糊。另外,什么是subject_id?是一个id字段,用于确定认可是属于用户还是投资组合? 投资组合是否同时具有user_id和portfolio_id,或者它是一个还是另一个但不是两者都有?

答案 1 :(得分:1)

经过几次阅读后,我想我得到了你说的话。试试这个。

SELECT users.id
    ,COUNT(portfolios.id) * 50 + 
     COUNT(VIEWS.id) * 2 + 
     COUNT(favorites.id) * 10 + 
     COUNT(e1.id) * 2 + 
     COUNT(e2.id) * 2 
     AS total
FROM users
LEFT JOIN portfolios
    ON portfolios.user_id = users.id
LEFT JOIN VIEWS
    ON VIEWS.subject_id = portfolios.id
LEFT JOIN favorites
    ON favorites.subject_id = portfolios.id
LEFT JOIN endorsements e1
    ON e1.portfolio_id = portfolios.id
LEFT JOIN endorsements e2
    ON e2.user_id = users.id
GROUP BY users.id
ORDER BY total DESC LIMIT 8

我认为与用户或投资组合相关的认可。我不知道你的价值观在你的牌桌上是什么样的,但理论上,由于认可与用户或投资组合有关,但投资组合总是与用户有关,因此加入两者都不是绝对必要的。 user_id或portfolio_id。在这种情况下,它会发现将用户表加入到e1的批注中,并将投资组合表作为e2加入到代言中,然后添加它们。

答案 2 :(得分:1)

如果GROUP BY查询中有多个外部联接,则必须be careful of double-counting。因此,我会将COUNT(portfolios.id)更改为COUNT(DISTINCT portfolios.id)等。这也应该消除了对CASE语句的需求。获得这些计数后,您可以按照您在问题中所说的(* 2* 50或您喜欢的任何内容)乘以其得分值。