带有连接的SQL复杂查询

时间:2015-07-20 12:34:09

标签: sql ruby-on-rails postgresql

我遇到一个查询问题。 让我解释一下我想要的东西: 为了简洁起见,我们说我有三张桌子:

-Offers

-Ratings

-Users

现在我想要做的是创建SQL查询:

  1. 我希望优惠能够列出所有字段和其他临时列,而不是任何名为AverageUserScore的临时列。

  2. 此AverageUserScore是抓取所有优惠的产品,属于特定用户,然后获取属于这些优惠的所有评分,然后评估平均评分 - 此平均分数为AverageUserScore。

  3. 为了进一步解释,我需要这个Ruby on Rails应用程序的查询。在浏览器内部应用程序中,您可以看到其他用户的所有优惠,最后一列是AverageUserScore,作为最后一列。

    协会

    1. 优惠有很多评分
    2. 优惠属于用户
    3. 评级属于报价
    4. 用户有很多优惠

1 个答案:

答案 0 :(得分:2)

做出的假设:

  • 您的评分模型中实际上有一个数字列(任何类型的SQL AVG都可以使用)。我在我的示例中使用了一列ratings.rating
  • AverageUserScoreunconventional,因此average_user_score更好。
  • 您不介意没有获得没有优惠的用户:无论如何都没有为他们明确定义平均评分。
  • 您没有偏离Rails的约定,只能使用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