可以轨吗? Active Record 处理 SQL 聚合查询吗?
刚刚开始学习活动记录,我想知道如何最好地从涉及 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"
这是示例 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
Just started learning active record and am wondering how to best retrieve data from multiple tables where an SQL aggregate query is involved.
In the following example (from a medical app) I'm looking for the most recent events of various types for each patient (e.g. last visit, last labtest etc). As you can see from the sql query below I'm looking for the max(date) value from a grouped query. I resorted to find_by_sql to do this - however I'd like to see how to do this without using find_by_sql.
IOW - how would you get the required data here using a pure ActiveRecord approach. Below are the Table and Class defs I'm testing with:
Find by Sql to retrieve most recent entries for each type - note the 'max(event_date)' here
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"
Here's the sample sql query result:
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
Classes
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如 Pallan 指出的,
:select
选项不能与:include
选项一起使用。 但是:joins
选项可以。 这就是您想要的。 事实上,它可以采用与:include
相同的参数或使用您自己的 SQL。 这是一些粗糙的、未经测试的代码,可能需要一些小的修改。请注意,我稍微修改了一些内容。 我将
event_date
别名重命名为max_date
,这样就不会混淆您所指的属性。:select
查询中使用的属性在返回的模型中可用。 例如,在此您可以调用event.max_date
。 我还添加了事件id
列,因为如果没有id
属性,有时您可能会遇到一些令人讨厌的错误(取决于您如何使用返回的模型)。:include
和:joins
之间的主要区别在于前者执行关联模型的预先加载。 换句话说,它将自动获取每个事件关联的患者对象。 这需要控制select
语句,因为它需要同时选择患者属性。 使用:joins
患者对象不会被实例化。As Pallan pointed out, the
:select
option cannot be used with the:include
option. However the:joins
option can. And this is what you want here. In fact, it can take the same arguments as:include
or use your own SQL. Here's some rough, untested code, may need some minor fiddling.Note I modified things slightly. I renamed the
event_date
alias tomax_date
so there's no confusion over which attribute you are referring to. The attributes used in your:select
query are available in the models returned. For example, in this you can callevent.max_date
. I also added the eventid
column because you can sometimes get some nasty errors without anid
attribute (depending on how you use the returned models).The primary difference between
:include
and:joins
is that the former performs eager loading of the associated models. In other words, it will automatically fetch the associated patient object for each event. This requires control of theselect
statement because it needs to select the patient attributes at the same time. With:joins
the patient objects are not instantiated.include 只是一个巧妙的左连接,您可以在 .find 中将其与 select 和 group_by 结合使用
An include is just a clever left join, you can use that in conjuction with select and group_by in your .find
在当前版本的 AR (2.3) 中,我认为您唯一的选择是使用 find_by_sql。 为什么? 您的自定义 SELECT 属性。 ActiveRecord 允许在 find 调用中使用 :select 和 :include 参数。 不幸的是它们不能一起使用。 如果同时指定 :select 将被忽略。 在您的示例中,您需要选择来限制列并获取 MAX 函数。
我听说有一个补丁/黑客可以让它们一起工作,但我不确定它在哪里。
同行
In the current version of AR (2.3) I think your only option is to use find_by_sql. Why? Your custom SELECT attributes. ActiveRecord allows :select and :include arguments to the find call. Unfortunately they can't be used together. If you specify both the :select will be ignored. In your example you need the select to limit your columns and to get your MAX function.
I've heard there is a patch/hack to get them to work together, but I am not sure where it is.
Peer