刚刚开始学习活动记录,我想知道如何从涉及SQL聚合查询的多个表中最佳地检索数据。
在以下示例中(来自医疗应用程序)我正在为每位患者寻找各种类型的最新事件(例如,上次访问,最后一次实验室测试等)。正如您从下面的SQL查询中看到的,我正在寻找分组查询中的max(date)值。我使用find_by_sql来执行此操作 - 但是我想看看如何在不使用find_by_sql的情况下执行此操作。
IOW - 如何使用纯ActiveRecord方法获取所需数据。下面是我正在测试的表和类defs:
通过Sql查找以检索每种类型的最新条目 - 请注意这里的'max(event_date)'
strsql = "select p.lname, e.patient_id, e.event_type, max(e.event_date) as event_date
from events e
inner join patients p on e.patient_id = p.id
group by p.lname, e.patient_id, e.event_type"
以下是示例sql查询结果:
lname, patient_id, event_type, latest 'Hunt', 3, 'Labtest', '2003-05-01 00:00:00' 'Hunt', 3, 'Visit', '2003-03-01 00:00:00' 'Seifer', 2, 'Labtest', '2002-05-01 00:00:00' 'Seifer', 2, 'Visit', '2002-03-01 00:00:00' Table Relationships are: Tables ---> Patients --> Events --> visits --> labtests --> ... other patients t.string :lname t.date :dob events t.column :patient_id, :integer t.column :event_date, :datetime t.column :event_type, :string visits t.column :event_id, :integer t.column :visittype, :string labtests t.column :event_id, :integer t.column :testtype, :string t.column :testvalue, :string
类
class Patient < ActiveRecord::Base
has_many :events
has_many :visits, :through =>:events
has_many :labtests, :through => :events
end
class Event < ActiveRecord::Base
has_many :visits
has_many :labtests
belongs_to :patient
end
class Visit < ActiveRecord::Base
belongs_to :event
end
class Labtest < ActiveRecord::Base
belongs_to :event
end
答案 0 :(得分:14)
正如Pallan所指出的,:select
选项不能与:include
选项一起使用。但是:joins
选项可以。这就是你想要的。实际上,它可以采用与:include
相同的参数或使用您自己的SQL。这是一些粗略的,未经测试的代码,可能需要一些小的摆弄。
Event.all(:select => "events.id, patients.lname, events.patient_id, events.event_type, max(events.event_date) as max_date", :joins => :patient, :group => "patients.lname, events.patient_id, events.event_type")
注意我稍微修改了一些东西。我将event_date
别名重命名为max_date
,因此您不会混淆您所指的属性。您返回的模型中提供了:select
查询中使用的属性。例如,您可以在此处拨打event.max_date
。我还添加了事件id
列,因为如果没有id
属性,您有时可能会遇到一些令人讨厌的错误(取决于您使用返回的模型的方式)。
:include
和:joins
之间的主要区别在于前者执行关联模型的急切加载。换句话说,它将自动为每个事件获取相关的患者对象。这需要控制select
语句,因为它需要同时选择患者属性。使用:joins
时,患者对象不会被实例化。
答案 1 :(得分:2)
包含只是一个聪明的左连接,您可以在.find
中将其与select和group by结合使用答案 2 :(得分:0)
在当前版本的AR(2.3)中,我认为您唯一的选择是使用find_by_sql。为什么?您的自定义SELECT属性。 ActiveRecord允许:select和:包含查找调用的参数。不幸的是它们不能一起使用。如果同时指定:select将被忽略。在您的示例中,您需要select来限制列并获得MAX函数。
我听说有一个补丁/黑客让他们一起工作,但我不知道它在哪里。
对等