Pregunta

Recién comencé a aprender el registro activo y me pregunto cómo recuperar mejor los datos de varias tablas donde está involucrada una consulta agregada SQL.

En el siguiente ejemplo (de una aplicación médica), estoy buscando los eventos más recientes de varios tipos para cada paciente (por ejemplo, última visita, última prueba de laboratorio, etc.). Como puede ver en la consulta sql a continuación, estoy buscando el valor máximo (fecha) de una consulta agrupada. Recurrí a find_by_sql para hacer esto; sin embargo, me gustaría ver cómo hacerlo sin usar find_by_sql.

IOW: ¿cómo obtendría los datos requeridos aquí utilizando un enfoque ActiveRecord puro? A continuación se muestran las definiciones de tabla y clase con las que estoy probando:

Buscar por SQL para recuperar las entradas más recientes para cada tipo: tenga en cuenta el 'max (event_date)' aquí

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"

Aquí está el resultado de la consulta SQL de muestra:

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

Clases

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
¿Fue útil?

Solución

Como señaló Pallan, la opción : select no se puede usar con la opción : include . Sin embargo, la opción : une puede. Y esto es lo que quieres aquí. De hecho, puede tomar los mismos argumentos que : include o usar su propio SQL. Aquí hay un código aproximado, no probado, que puede necesitar algunos pequeños retoques.

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: modifiqué un poco las cosas. Cambié el nombre del alias event_date a max_date para que no haya confusión sobre a qué atributo se refiere. Los atributos utilizados en su consulta : select están disponibles en los modelos devueltos. Por ejemplo, en esto puede llamar a event.max_date . También agregué la columna de evento id porque a veces puedes obtener algunos errores desagradables sin un atributo id (dependiendo de cómo uses los modelos devueltos).

La principal diferencia entre : include y : une es que el primero realiza una carga entusiasta de los modelos asociados. En otras palabras, buscará automáticamente el objeto de paciente asociado para cada evento. Esto requiere el control de la declaración select porque necesita seleccionar los atributos del paciente al mismo tiempo. Con : une los objetos del paciente no se instancian.

Otros consejos

Una inclusión es solo una combinación izquierda inteligente, puede usarla junto con select y group by en su .find

En la versión actual de AR (2.3) creo que su única opción es usar find_by_sql. ¿Por qué? Tus atributos SELECT personalizados. ActiveRecord permite: seleccionar e: incluir argumentos para la llamada de búsqueda. Lamentablemente no se pueden usar juntos. Si especifica ambos, se ignorará: select. En su ejemplo, necesita seleccionar para limitar sus columnas y obtener su función MAX.

Escuché que hay un parche / pirateo para que trabajen juntos, pero no estoy seguro de dónde está.

Par

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top