我遇到一个查询问题。 让我解释一下我想要的东西: 为了简洁起见,我们说我有三张桌子:
-Offers
-Ratings
-Users
现在我想要做的是创建SQL查询:
我希望优惠能够列出所有字段和其他临时列,而不是任何名为AverageUserScore的临时列。
此AverageUserScore是抓取所有优惠的产品,属于特定用户,然后获取属于这些优惠的所有评分,然后评估平均评分 - 此平均分数为AverageUserScore。
为了进一步解释,我需要这个Ruby on Rails应用程序的查询。在浏览器内部应用程序中,您可以看到其他用户的所有优惠,最后一列是AverageUserScore,作为最后一列。
协会
答案 0 :(得分:2)
做出的假设:
AVG
都可以使用)。我在我的示例中使用了一列ratings.rating
。AverageUserScore
为unconventional,因此average_user_score
更好。id
以外的主键。为每个用户显示优惠是一项简单的任务:在@users.each do |user|
的循环中,您可以执行user.offers.each do |offer|
并进行设置。这里唯一的问题是它将为每个用户执行单独的查询。不好。
“提取优惠”部分是标准的N + 1计数器,甚至可见in the guides。
@users = User.includes(:offers).all
这里有趣的部分只是获得平均值。
为此,我将使用Arel。它已经是Rails的一部分,ActiveRecord是建立在它之上的,所以你不需要额外安装任何东西。
您应该能够像这样进行连接:
User.joins(offers: :ratings)
这不会让你感兴趣(除了过滤没有优惠的用户)。尽管如此,你会得到一大堆每个评级加上相应的优惠和该优惠的用户。由于我们采用的是每位用户的平均值,因此我们需要group by users.id
,每个users.id
值有效地输入一个条目。也就是说,每个用户一个。一个用户列表,是的!
让我们暂停一下,做一些分配,使Arel相关代码更漂亮。事实上,我们只需要两个:
users = User.arel_table
ratings = Rating.arel_table
好。所以。我们需要获取用户列表(所有字段),并为每个用户获取其商品“评级”rating
字段中显示的平均值。让我们编写这些SQL表达式:
# users.*
user_fields = users[Arel.star] # Arel.star is a portable SQL "wildcard"
# AVG(ratings.rating) AS average_user_score
average_user_score = ratings[:rating].average.as('average_user_score')
全部设置。为最终查询做好准备:
User.includes(:offers) # N+1 counteraction
.joins(offers: :ratings) # dat join
.select(user_fields, average_user_score) # fields we need
.group(users[:id]) # grouping to only get one row per user