2009-08-01 57 views
9

剛剛開始學習活動記錄,想知道如何從涉及SQL聚合查詢的多個表中最好地檢索數據。Can Rails的Active Record處理SQL聚合查詢嗎?

在以下示例中(來自醫療應用程序),我正在爲每個患者尋找各種類型的最近事件(例如上次訪問,上次實驗室等)。正如你可以從下面的sql查詢中看到的,我正在從分組查詢中查找最大值(日期)值。我使用find_by_sql來做到這一點 - 但是我想看看如何在不使用find_by_sql的情況下做到這一點。

IOW - 您將如何使用純ActiveRecord方法獲得所需的數據。

查找SQL來獲取最新的條目爲每種類型 - 請注意,「最大(活動日期)」在這裏

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查詢:下面是表和類DEFS我與測試結果:

 
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 

回答

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

注意我稍微修改了一些東西。我將event_date別名更名爲max_date,因此不會對您所指的屬性造成混淆。返回的模型中提供了您的:select查詢中使用的屬性。例如,在這裏你可以撥打event.max_date。我還添加了事件id列,因爲如果沒有id屬性(取決於您如何使用返回的模型),有時可能會出現一些令人討厭的錯誤。

:include:joins之間的主要區別在於前者執行相關模型的熱切加載。換句話說,它會自動爲每個事件獲取關聯的患者對象。這需要控制select聲明,因爲它需要同時選擇患者屬性。通過:joins,患者對象未被實例化。

+0

從OP快速跟進。有一個小調整:連接(vs:join)Ryan的代碼工作並替換了我原始文章中的Find_By_Sql查詢。很酷。然而,我只是注意到(AFAIK)並不是所有的SQL查詢都可以通過ORM調用來實現(例如聯合查詢,它結合了表中的最小值和最大值)。我懷疑這需要通過ORM進行2次單獨的調用,而Find_By_Sql可以在1次調用中完成。 find_by_sql(「從表t中選擇最小值(t.Event_Date)從表t中選擇最大值(t.Event_Date)」) – BrendanC 2009-08-04 04:12:40

0

在AR(2.3)的最新版本,我認爲喲你唯一的選擇是使用find_by_sql。爲什麼?您的自定義SELECT屬性。 ActiveRecord允許:選擇和:爲查找調用包含參數。不幸的是,它們不能一起使用。如果同時指定:select將被忽略。在你的例子中,你需要select來限制你的列並獲得你的MAX函數。

我聽說有一個補丁/黑客讓他們一起工作,但我不知道它在哪裏。

同行

+0

有沒有辦法使用顯式:連接而不是和包含來解決這個限制?這會是一個選擇嗎? – BrendanC 2009-08-02 02:08:49

2

的包括僅僅是一個聰明的左連接,您可以使用在一起選擇與選擇和GROUP_BY在.find

相關問題