Rails的Active Record可以处理SQL聚合查询吗?
刚开始学习活动记录,我想知道如何最好地从涉及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,'访问','2002-03-01 00:00:00' 表关系是: 表--->患者 - >事件 - >访问 - >实验室 - > ......其他 耐心 t.string:lname t.date:dob 事件 t.column:patient_id,:整数 t.column:event_date,:datetime t.column:event_type,:string 访问 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 :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
正如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
别名重命名为event_date
,因此不会混淆您所指的属性。 您的:select
查询中使用的属性在返回的模型中可用。 例如,您可以在event.max_date
调用event.max_date
。 我还添加了事件id
列,因为有时你可以在没有id
属性的情况下得到一些讨厌的错误(取决于你如何使用返回的模型)。
以下:include
和:joins
之间的主要区别在于前者执行关联模型的急切加载。 换句话说,它将自动为每个事件获取相关的患者对象。 这需要控制select
语句,因为它需要同时选择患者属性。 用:joins
患者对象未实例化。
include只是一个聪明的左连接,你可以在.find中与select和group_by结合使用
在当前版本的AR(2.3)中,我认为您唯一的选择是使用find_by_sql。 为什么? 您的自定义SELECT属性。 ActiveRecord允许:select和:包含查找调用的参数。 不幸的是它们不能一起使用。 如果同时指定:select将被忽略。 在您的示例中,您需要select来限制列并获得MAX函数。
我听说有一个补丁/黑客让他们一起工作,但我不知道它在哪里。
窥视