Mysql 轨道以最大条件连接
鉴于这两种模式Mysql 轨道以最大条件连接,mysql,ruby-on-rails,activerecord,join,max,Mysql,Ruby On Rails,Activerecord,Join,Max,鉴于这两种模式 class Article < AR::Base belongs_to :tag default_scope order('id DESC') end class Tag < AR::Base has_many :articles scope :featured, order(:ordering).limit(5) end 以这种方式编写的代码具有以下优点:我正在尝试对其进行优化,因为它将非常频繁地运行。我排除了功能范围中的includes调用
class Article < AR::Base
belongs_to :tag
default_scope order('id DESC')
end
class Tag < AR::Base
has_many :articles
scope :featured, order(:ordering).limit(5)
end
以这种方式编写的代码具有以下优点:我正在尝试对其进行优化,因为它将非常频繁地运行。我排除了功能范围中的includes
调用,因为它将加载前5个标记中的所有文章(很多文章…)
在普通的旧SQL中,我可以使用如下查询将这两个表连接起来
SELECT tag_id, MAX(id) FROM articles GROUP BY tag_id
# or in Rails
Article.select('MAX(id), tag_id').group(:tag_id)
+--------+---------+
| tag_id | MAX(id) |
+--------+---------+
| 14 | 26787 |
...
| 1 | 27854 |
| 5 | 27780 |
| 0 | 10953 |
+--------+---------+
作为联接表,我可以通过一个查询检索所有数据
如何将其移植到Rails和ActiveRecord中
更新
我需要在AR上下文中执行的完整查询是
SELECT a.*, t.*
FROM tags t
JOIN (SELECT MAX(id) AS latest, tag_id FROM articles GROUP BY tag_id) j ON j.tag_id = t.id
JOIN articles p ON j.latest = a.id
LIMIT 5
我使用最新的查询尝试了AR#find_by_sql
方法,我得到了正确的结果集,但无法在对象中导航
sql = '...' # This holds the previous query
Tag.find_by_sql(sql).first.class
=> "Tag"
Tag.find_by_sql(sql).first.articles.first
=> nil # why???
更新2
也试过了
Tag.joins('JOIN ... all my query join part here ...').first.articles.first
=> nil
然而,我注意到我可以直接使用我的文章字段作为标记字段,也就是说,我可以写作
Tag.find_by_sql(...).first.title # where title is a field of Article class
Tag.joins(...).first.title # where title is a field of Article class
但是很明显,我不能调用文章实例方法。找到了我问题的部分解决方案。我可以通过两个查询获取所需的记录,并且仍然将数据作为AR对象加载:
# This will fetch the needed article ids
ids = Article.select('MAX(id) as max_id').group(:tag_id).map(&:max_id)
# This return the top tags each one with the article needed in articles.first
Tag.includes(:articles).where('article.id IN (?)', ids).limit(5).each do |t|
t.name # gives the tag name
t.articles # gives [<#Article...>] i.e. an array with a single article
end
因为。看来是这样
仍然在寻找更好的答案,可能是一个连接,比如我问题中加载AR对象的连接。我将自行接受我自己的答案,因为没有其他答案。
# This will fetch the needed article ids
ids = Article.select('MAX(id) as max_id').group(:tag_id).map(&:max_id)
# This return the top tags each one with the article needed in articles.first
Tag.includes(:articles).where('article.id IN (?)', ids).limit(5).each do |t|
t.name # gives the tag name
t.articles # gives [<#Article...>] i.e. an array with a single article
end
where('article.id IN (SELECT MAX(id) from articles)')