【问题标题】:How to use `to_sql` in AREL when using `average()`?使用`average()`时如何在AREL中使用`to_sql`?
【发布时间】:2011-07-07 13:53:04
【问题描述】:

我正在尝试从 AREL 获取 SQL,但如果我使用 average(:stars) 则它不起作用:

这行得通:

Review.where("reviewed_user_id = ?", self.reviewed_user_id).to_sql
#=> "SELECT `reviews`.* FROM `reviews` WHERE (reviewed_user_id = 3)"

这会导致NoMethodError:

Review.where("reviewed_user_id = ?", self.reviewed_user_id).average(:stars).to_sql
#=> undefined method `to_sql' for 3:Fixnum

这意味着to_sql 是在 AREL 的结果上而不是在 AREL 对象上被调用 - 但为什么呢?

如何获取生成的SQL?

【问题讨论】:

    标签: ruby-on-rails-3 activerecord


    【解决方案1】:

    发生这种情况的原因是平均方法在ActiveRecord::Relation 上,而不是在 Arel 上,这会强制计算。

    m = Review.where('id = ?', 42).method(:average)
    #=> #<Method: ActiveRecord::Relation(ActiveRecord::Calculations)#average>
    m.source_location  # or m.__file__ if you're on a different version of Ruby
    #=> ["/Users/jtran/.rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.4/lib/active_record/relation/calculations.rb", 65]
    

    通过查看ActiveRecord::Calculations 的内部结构,您可以了解如何获取它使用的 SQL。

    my_reviewed_user_id = 42
    relation = Review.where('reviewed_user_id = ?', my_reviewed_user_id)
    column = Arel::Attribute.new(Review.unscoped.table, :stars)
    relation.select_values = [column.average]
    relation.to_sql
    #=> "SELECT AVG(\"reviews\".\"stars\") AS avg_id FROM \"reviews\" WHERE (reviewed_user_id = 42)"
    

    如果您在控制台上工作,请小心。 ActiveRecord::Relation 缓存了一些东西,所以如果你逐行在控制台中输入上面的内容,它实际上是行不通的,因为漂亮的打印会强制关系。但是,用分号分隔上述内容并且没有新行将起作用。

    或者,您可以直接使用 Arel,如下所示:

    my_reviewed_user_id = 42
    reviews = Arel::Table.new(:reviews)
    reviews.where(reviews[:reviewed_user_id].eq(my_reviewed_user_id)).project(reviews[:stars].average).to_sql
    #=> "SELECT AVG(\"reviews\".\"stars\") AS avg_id FROM \"reviews\" WHERE \"users\".\"reviewed_user_id\" = 42"
    

    【讨论】:

    • 超级!感谢您分享您用来解决这个问题的方法.. 将来会派上用场!
    • 这就是我喜欢 Ruby 的原因。你可以随时询问 REPL 和来源。它是不止一种意义上的来源!
    • 这在许多不同的逻辑中帮助了我很多。伟大的工作人员。
    猜你喜欢
    • 1970-01-01
    • 2012-03-07
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 2014-12-14
    相关资源
    最近更新 更多