2009-08-01 16 views
9

Sadece aktif kayıtları öğrenmeye başladım ve SQL toplama sorgusunun yer aldığı birden fazla tablodan en iyi verileri nasıl alacağımı merak ediyorum. (Tıbbi app) şu örnekte Can Rails 'Active Record Tutamadı SQL toplama sorguları?

Her hasta için çeşitli En son olaylar (örn son ziyaretten son labtest vs) arıyorum. Aşağıdaki sql sorgudan görebildiğiniz gibi, gruplandırılmış bir sorgudan maksimum (tarih) değerini arıyorum. Bunu yapmak için find_by_sql'e başvurdum - ancak find_by_sql'yi kullanmadan bunun nasıl yapıldığını görmek isterim.

IOW - Burada saf ActiveRecord yaklaşım kullanarak gerekli verileri almak nasıl. Her tür için en son girdileri almak için Sql tarafından

Bul - not 'max (EVENT_DATE)' burada

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" 

İşte örnek sql sorgusu var: Aşağıda Tablo ve Sınıf defs Birlikte test ediyorum edilir sonuç:

 
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 

Sınıflar AR (2.3) mevcut sürümünde

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 

cevap

14

, :select seçenek :include ile kullanılamaz sizin .find seçin ve group_by ile paralel olarak kullanabileceğiniz gibi katılmak olduğunu seçeneği. Ancak :joins seçeneği olabilir. Ve burada istediğin bu. Aslında, :include ile aynı argümanları alabilir veya kendi SQL'inizi kullanabilir. İşte bazı kaba, denenmemiş kodlar, biraz küçük şeytan gerekebilir.

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

Not Öğeleri biraz değiştirdim. event_date diğer adını max_date olarak yeniden adlandırdım, dolayısıyla atıfta bulunduğunuz öznitelik hakkında hiçbir karışıklık yok. :select sorgunuzda kullanılan özellikler, döndürülen modellerde bulunur. Örneğin, bu konuda event.max_date'u arayabilirsiniz. id sütununu ekledim, çünkü bazen id özniteliği olmadan bazı hatalı hataları alabilirsiniz (döndürülen modelleri nasıl kullandığınıza bağlı olarak).

:include ve :joins arasındaki birincil fark, ilgili modellerin istekli yüklemesini gerçekleştirmesidir. Diğer bir deyişle, her olay için ilişkili hasta nesnesini otomatik olarak getirecektir. Bu, select ifadesinin denetimini gerektirir çünkü hasta özniteliklerini aynı anda seçmesi gerekir. :joins ile hasta nesneleri başlatılamıyor.

+0

OP'den buradan hızlı bir şekilde takip edin.1 küçük tweak ile: birleştirir (vs: birleştirme) Ryan'ın kodu çalışır ve orijinal gönderiimde Find_By_Sql sorgusunun yerini alır. Çok havalı. Ancak geçerken (AFAIK) tüm SQL sorgularının ORM çağrıları ile uygulanamayacağını (örneğin, bir tablodan Min ve Maks değerlerini birleştiren Birleşim Sorgusu) not edeceğim. Bunun, ORM üzerinden 2 ayrı çağrı gerektireceğinden şüpheleniyorum, buna karşılık bir Find_By_Sql, 1 aramada ör. find_by_sql ("Min (t.Event_Date) tablosunu seçin t Birleşim Tablodan" Max (t.Event_Date) "seçeneğini seçin.) – BrendanC

+0

Kullanılacak orijinal gönderi güncellendi: birleştirmeler. Yine de haklısınız, her sorgu ORM ile yapılamaz ve bu Active Record'un amacı değildir. İhtiyaçların çoğuna iyi uyacak ve geri kalanını find_by_sql ile bırakabilecek şekilde tasarlanmıştı. Her şeyi yapmaya çalışmaz, bu yüzden işinize daha iyi uyuyorsa find_by_sql'yi kullanmaktan çekinmeyin. – ryanb

0

bence yo ur sadece seçim find_by_sql kullanmaktır. Niye ya? Özel SELECT özellikleriniz. ActiveRecord şunları sağlar: select ve: find çağrısına argümanlar ekleyin. Maalesef birlikte kullanılamazlar. Her ikisini de belirtirseniz: seçim yok sayılır. Örneğinizde, sütunlarınızı sınırlamak ve MAX işlevinizi almak için seçime ihtiyacınız vardır.

Ben bir yama/Birlikte çalışmayı almak için kesmek olduğunu duymuştum, ama nerede olduğunu emin değilim.

Peer

+0

Açık kullanmanın bir yolu var mı: Bu sınırlamayı aşmak yerine yerine katılın ve dahil edin? Bu bir seçenek olabilir mi? – BrendanC

2

Bir dahil sadece akıllı sol Eğer Pallan belirttiği gibi

İlgili konular