我使用 Rails 4.2.0 和 ActiveRecord。我有 Case
模型,其中 has_many :notes
。
我的主要目标是在一个查询中获取每个案例的最新注释。注释字段应该是可排序的(例如,ORDER BYnotes.created_at
)我可以通过这样的 SQL 查询来实现这一点:
SELECT cases.*, notes.* FROM cases
LEFT OUTER JOIN notes ON cases.id = notes.case_id AND notes.id = (
SELECT id FROM notes
WHERE notes.case_id = cases.id
ORDER BY notes.created_at DESC
LIMIT 1
)
ORDER BY notes.created_at DESC
我当前的case.rb
代码如下:
has_one :latest_note, -> do
where('id' => Note.where('"case_id" = "cases"."id"').order(created_at: :desc).limit(1))
end, inverse_of: :case, class_name: 'Note'
使用eager_load
时效果很好:Case.eager_load(:latest_note).order('notes.created_at DESC')
SELECT "cases"."id" AS t0_r0, "cases"."created_at" AS t0_r1, "cases"."updated_at" AS t0_r2, "notes"."id" AS t1_r0, "notes"."case_id" AS t1_r1, "notes"."created_at" AS t1_r2, "notes"."updated_at" AS t1_r3
FROM "cases" LEFT OUTER JOIN "notes"
ON "notes"."case_id" = "cases"."id"
AND "notes"."id" IN (
SELECT "notes"."id" FROM "notes"
WHERE ("case_id" = "cases"."id")
ORDER BY "notes"."created_at" DESC
LIMIT 1
) ORDER BY notes.created_at DESC
但是会引发错误SQLite3::SQLException:没有这样的列:cases.id
而没有eager_load
:
Case.first.latest_note
SELECT "notes".* FROM "notes"
WHERE "notes"."case_id" = ? AND "notes"."id" IN (
SELECT "notes"."id" FROM "notes"
WHERE ("case_id" = "cases"."id")
ORDER BY "notes"."created_at" DESC
LIMIT 1
) LIMIT 1
附注有没有没有关联范围的解决方案?通过 joins
进行的原始左连接不适用于 eager_load
。如果没有 eager_load
,它不会将值从数据库映射到对象 - 日期保留为字符串,而不是 DateTime
对象。
最佳答案
我刚刚找到了解决方法:
来自documentation我发现,该作用域可以接受所有者对象作为参数:
class User < ActiveRecord::Base
has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
end
所以,我的关系变成了:
has_one :latest_note, ->(kase) do
subquery = Note.order(created_at: :desc).limit(1)
subquery = kase.is_a?(Case) ? subquery.where(case_id: kase.id) : subquery.where('"case_id" = "cases"."id"')
where('id' => subquery)
end, inverse_of: :case, class_name: 'Note'
但是,Rails 4.2.0
输出:
DEPRECATION WARNING: The association scope 'latest_note' is instance dependent (the scope block takes an argument). Preloading happens before the individual instances are created. This means that there is no instance being passed to the association scope. This will most likely result in broken or incorrect behavior. Joining, Preloading and eager loading of these associations is deprecated and will be removed in the future.
此外,此解决方法不适用于预加载
(单独的 SQL 查询)
关于ruby-on-rails - Rails 关联范围中左连接的子查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28817477/