Activerecord:将 ruby 方法转移到 sql-land
Activerecord: Transfer ruby methods to sql-land
我在 rails 应用程序中有以下架构
我的页面有很多 load_times(这是一个多态关联)。我想获取每个页面的最新 created_at
load_time,然后从中获取最大 load_time 字段编号(希望同名字段不会让您感到困惑)。这是我目前使用的方法,但使用 ruby 方法:
pages.includes(:load_times).group(:resource_id).select("load_times.load_time, max(load_times.created_at) as date").reject{|lt| lt.load_time.nil?}.sort_by { |pg| pg.load_time.load_time }.last
如何将 reject
和 sort_by
ruby 方法转移到 sql 土地?
这个怎么样:
pages
.joins(:load_times)
.group(:resource_id)
.select("pages.*, load_times.load_time, MAX(load_times.created_at) as date")
.where.not(load_times: { load_time: nil })
.order("load_times.load_time")
.last
请注意 where.not
仅 Rails >= 4。如果您在 Rails 3 中,您可以将其替换为 where("load_times.load_time IS NOT NULL")
在评论中明确了想要的结果后,这是获取最慢load_time的Page对象的查询,只考虑了最近的load_time
条记录的[=56] =].请注意,您通常可以在带有 MAX(load_times.created_at)
或 MAX(load_times.id)
的 having 子句中无差别地获得该结果,后者效率更高一些。如果这样做,请将所有对 created_at
的引用更改为 id
。
pages
.joins(:load_times)
.where.not(load_times: { load_time: nil })
.group('load_times.created_at')
.having('load_times.created_at = MAX(load_times.created_at)')
.order('load_times.load_time DESC')
.first
编辑
经过更多研究(是的,我个人认为 ;)),我终于让您的查询正常工作。您需要加入 load_times
table 两次,使用加入条件中每个 Page
的最后一行。
此外,对于第二个联接,您需要使用单个列来标识 load_times
的最后一个条目。 created_at
可能无法正常工作,因为您的 load_times
table 可能有两个 created_at
相同的条目。也许这不是你的情况,但以防万一我使用 id
,因为它与 created_at
具有相同的顺序并且是唯一的。
此外,我删除了 where.not(load_times: { load_time: nil })
位,因为我假设您想要在其上获取具有 load_time
属性的最后一个 load_time
元素。
最后,我假设了一个多态关联,因此 resource_type = 'Page'
。
开始了:
pages
.joins(:load_times)
.joins("INNER JOIN (SELECT l1.page_id, MAX(l1.id) AS max_id FROM load_times as l1 GROUP BY l1.page_id) l2 ON load_times.page_id = l2.page_id AND load_times.id = l2.max_id AND resource_type = 'Page'")
.order("load_times.load_time DESC")
.first
感谢发人深省的问题,学到不少东西
继续@dgilperez 的工作,我认为这可能 return 您的目标值:
pages
.joins(:load_times)
.where.not(load_times: { load_time: nil })
.group(:resource_id)
.select('pages.*, MAX(load_times.load_time) as load_time, MAX(load_times.created_at) as max_created_at')
我在 rails 应用程序中有以下架构
我的页面有很多 load_times(这是一个多态关联)。我想获取每个页面的最新 created_at
load_time,然后从中获取最大 load_time 字段编号(希望同名字段不会让您感到困惑)。这是我目前使用的方法,但使用 ruby 方法:
pages.includes(:load_times).group(:resource_id).select("load_times.load_time, max(load_times.created_at) as date").reject{|lt| lt.load_time.nil?}.sort_by { |pg| pg.load_time.load_time }.last
如何将 reject
和 sort_by
ruby 方法转移到 sql 土地?
这个怎么样:
pages
.joins(:load_times)
.group(:resource_id)
.select("pages.*, load_times.load_time, MAX(load_times.created_at) as date")
.where.not(load_times: { load_time: nil })
.order("load_times.load_time")
.last
请注意 where.not
仅 Rails >= 4。如果您在 Rails 3 中,您可以将其替换为 where("load_times.load_time IS NOT NULL")
在评论中明确了想要的结果后,这是获取最慢load_time的Page对象的查询,只考虑了最近的load_time
条记录的[=56] =].请注意,您通常可以在带有 MAX(load_times.created_at)
或 MAX(load_times.id)
的 having 子句中无差别地获得该结果,后者效率更高一些。如果这样做,请将所有对 created_at
的引用更改为 id
。
pages
.joins(:load_times)
.where.not(load_times: { load_time: nil })
.group('load_times.created_at')
.having('load_times.created_at = MAX(load_times.created_at)')
.order('load_times.load_time DESC')
.first
编辑
经过更多研究(是的,我个人认为 ;)),我终于让您的查询正常工作。您需要加入 load_times
table 两次,使用加入条件中每个 Page
的最后一行。
此外,对于第二个联接,您需要使用单个列来标识 load_times
的最后一个条目。 created_at
可能无法正常工作,因为您的 load_times
table 可能有两个 created_at
相同的条目。也许这不是你的情况,但以防万一我使用 id
,因为它与 created_at
具有相同的顺序并且是唯一的。
此外,我删除了 where.not(load_times: { load_time: nil })
位,因为我假设您想要在其上获取具有 load_time
属性的最后一个 load_time
元素。
最后,我假设了一个多态关联,因此 resource_type = 'Page'
。
开始了:
pages
.joins(:load_times)
.joins("INNER JOIN (SELECT l1.page_id, MAX(l1.id) AS max_id FROM load_times as l1 GROUP BY l1.page_id) l2 ON load_times.page_id = l2.page_id AND load_times.id = l2.max_id AND resource_type = 'Page'")
.order("load_times.load_time DESC")
.first
感谢发人深省的问题,学到不少东西
继续@dgilperez 的工作,我认为这可能 return 您的目标值:
pages
.joins(:load_times)
.where.not(load_times: { load_time: nil })
.group(:resource_id)
.select('pages.*, MAX(load_times.load_time) as load_time, MAX(load_times.created_at) as max_created_at')