Rails的Active Record可以处理SQL聚合查询吗?

Bre*_*anC 9 sql activerecord aggregate ruby-on-rails

刚刚开始学习活动记录,我想知道如何从涉及SQL聚合查询的多个表中最佳地检索数据.

在以下示例中(来自医疗应用程序)我正在为每位患者寻找各种类型的最新事件(例如,上次访问,最后一次实验室测试等).正如您从下面的SQL查询中看到的,我正在寻找分组查询中的max(date)值.我使用find_by_sql来执行此操作 - 但是我想看看如何在不使用find_by_sql的情况下执行此操作.

IOW - 如何使用纯ActiveRecord方法获取所需数据.下面是我正在测试的表和类定义:

通过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"
Run Code Online (Sandbox Code Playgroud)

这是示例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
Run Code Online (Sandbox Code Playgroud)

rya*_*anb 14

正如帕兰指出的那样,该: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")
Run Code Online (Sandbox Code Playgroud)

注意我稍微修改了一下.我将event_date别名重命名为,max_date因此不会混淆您所指的属性.:select返回的模型中提供了查询中使用的属性.例如,你可以在这里打电话event.max_date.我还添加了事件id列,因为有时你可以在没有id属性的情况下得到一些令人讨厌的错误(取决于你如何使用返回的模型).

:include和之间的主要区别在于:joins前者执行关联模型的急切加载.换句话说,它将自动为每个事件获取相关的患者对象.这需要控制select语句,因为它需要同时选择患者属性.随着:joins病人的对象不会被实例化.