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

发布于 2024-07-29 19:34:45 字数 1817 浏览 7 评论 0原文

刚刚开始学习活动记录,我想知道如何最好地从涉及 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

裂开嘴轻声笑有多痛 2024-08-05 19:34:45

正如 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 患者对象不会被实例化。

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.

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")

Note I modified things slightly. I renamed the event_date alias to max_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 call event.max_date. I also added the event id column because you can sometimes get some nasty errors without an id 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 the select statement because it needs to select the patient attributes at the same time. With :joins the patient objects are not instantiated.

养猫人 2024-08-05 19:34:45

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

秋心╮凉 2024-08-05 19:34:45

在当前版本的 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文