Domanda

Ho appena iniziato a studiare i record attivi e mi chiedo come recuperare al meglio i dati da più tabelle in cui è coinvolta una query aggregata SQL.

Nel seguente esempio (da un'app medica) sto cercando gli eventi più recenti di vario tipo per ciascun paziente (ad es. ultima visita, ultimo test di laboratorio, ecc.). Come puoi vedere dalla query sql di seguito, sto cercando il valore massimo (data) da una query raggruppata. Ho fatto ricorso a find_by_sql per farlo - tuttavia mi piacerebbe vedere come farlo senza usare find_by_sql.

IOW: come otterresti i dati richiesti qui usando un approccio ActiveRecord puro. Di seguito sono riportati i parametri di tabella e classe con cui sto testando:

Trova per SQL per recuperare le voci più recenti per ogni tipo. Nota qui il "max (data_evento)"

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"

Ecco il risultato della query sql di esempio:

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

Corsi

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
È stato utile?

Soluzione

Come ha sottolineato Pallan, l'opzione : select non può essere utilizzata con l'opzione : include . Tuttavia, l'opzione : joins può. E questo è quello che vuoi qui. In effetti, può accettare gli stessi argomenti di : include o utilizzare il proprio SQL. Ecco un po 'di codice approssimativo e non testato, potrebbe essere necessario un po' di confusione minore.

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

Nota: ho modificato leggermente le cose. Ho rinominato l'alias event_date in max_date , quindi non c'è confusione sull'attributo a cui ti riferisci. Gli attributi utilizzati nella query : select sono disponibili nei modelli restituiti. Ad esempio, in questo puoi chiamare event.max_date . Ho anche aggiunto la colonna id dell'evento perché a volte puoi ottenere alcuni errori spiacevoli senza un attributo id (a seconda di come usi i modelli restituiti).

La differenza principale tra : include e : join è che il primo esegue un caricamento desideroso dei modelli associati. In altre parole, recupererà automaticamente l'oggetto paziente associato per ciascun evento. Ciò richiede il controllo dell'istruzione select poiché deve selezionare contemporaneamente gli attributi del paziente. Con : join gli oggetti paziente non vengono istanziati.

Altri suggerimenti

Un'inclusione è solo un'intelligente unione a sinistra, puoi usarla insieme a select e raggruppare nel tuo .find

Nell'attuale versione di AR (2.3) penso che la tua unica opzione sia quella di usare find_by_sql. Perché? I tuoi attributi SELECT personalizzati. ActiveRecord consente: selezionare e: include argomenti per la chiamata find. Sfortunatamente non possono essere usati insieme. Se si specifica sia: selezionare verrà ignorato. Nel tuo esempio è necessario selezionare per limitare le colonne e ottenere la funzione MAX.

Ho sentito che esiste una patch / hack per farli lavorare insieme, ma non sono sicuro di dove sia.

Peer

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top