【问题标题】:Find_by_sql as a Rails scopeFind_by_sql 作为 Rails 范围
【发布时间】:2014-10-16 18:15:57
【问题描述】:

来自 Sitepoint 的 r937 非常友好地帮助我找出从数据库返回正确结果所需的查询。

我需要的是能够将此查询用作范围,并能够将其他范围链接到这个范围。

查询是:

SELECT coasters.*
FROM (
    SELECT order_ridden,
           MAX(version) AS max_version
    FROM coasters
    GROUP BY order_ridden
) AS m
INNER JOIN coasters
ON coasters.order_ridden = m.order_ridden
AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)

我尝试制作这样的范围:

  scope :uniques, lambda {
    find_by_sql('SELECT coasters.*
                 FROM (
                   SELECT order_ridden,
                          MAX(version) AS max_version
                   FROM coasters
                   GROUP BY order_ridden
                 ) AS m
                 INNER JOIN coasters
                 ON coasters.order_ridden = m.order_ridden
                 AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)')
  }

但是当我尝试将另一个示波器链接到它时,它失败了。有没有办法像普通范围一样运行此查询?

【问题讨论】:

    标签: sql ruby-on-rails chaining scopes


    【解决方案1】:

    find_by_sql 返回一个Array。但是您需要一个 ActiveRecord::Relation 来链接其他范围。

    使用返回 ActiveRecord::Relation 的 ActiveRecord 方法重写查询的一种方法是稍微重新排列它,以便嵌套在 INNER JOIN 部分中发生。

    您可能想尝试以下方法:

    scope :uniques, lambda {
      max_rows = select("order_ridden, MAX(version) AS max_version").group(:order_ridden)
      joins("INNER JOIN (#{max_rows.to_sql}) AS m
        ON coasters.order_ridden = m.order_ridden
       AND COALESCE(coasters.version,0) = COALESCE(m.max_version,0)")
    }
    

    【讨论】:

    • 嘿@cschroed 效果很好!谢谢。对于这实际上是如何工作的,我仍然有点困惑。我意识到我需要一个 ActiveRecord::Relation,但是如何重新排列你输出的 AR::Relation?
    • 很高兴它成功了!我们以一种可以使用称为joinsActiveRecord 查询方法而不是find_by_sql 的方式编写此代码。请参阅其他方法listed here。它们都返回一个ActiveRecord::Relation 并且可以被链接。如果使用Coaster.uniques.class,可以在Rails控制台查看返回值的类。
    猜你喜欢
    • 1970-01-01
    • 2015-06-25
    • 1970-01-01
    • 1970-01-01
    • 2019-01-16
    • 1970-01-01
    • 1970-01-01
    • 2012-02-13
    • 2016-07-11
    相关资源
    最近更新 更多