简体   繁体   中英

MySQL / Rails - Dynamically query a table field based on an attribute of each record

I've got a use case where I need to query for Appointment records based on their created_at or their start_on values. There are two types of appointments: 'Estimate' and 'GLA (go look at)' , represented by a type field with values 0 and 1.

If the appointment is of type Estimate, the query needs to use the start_on field - and if the appointment is a GLA, the query needs to use the created_at field, as GLA's are not scheduled and don't have start_on values.

Right now, I'm querying the data using a Rails scope to filter down properties who've had their last appointment from and to a certain date like so (the following shows 'from'):

scope :last_appointment_from, ->(date, type) {
  query = joins(:appointments)
  query = query.where('appointments.start_on = (
    SELECT MAX(appointments.start_on) 
    FROM appointments
    WHERE appointments.property_id = properties.id)')
  query = query.where('appointments.start_on >= ?', date)
  query
}

But this only queries the start_on value.

I've tried looking into doing GREATEST(MAX(start_on), MAX(created_at)) - but then I'm not sure how to know which field to know to use in the where('events.start_on >= ?', date) part.

After typing this out, I thought of another possible workaround - to just create another database field that gets updated with the corresponding date on an active record callback based on what type of Appointment it is, called query_field or something (and run a script to set that value for all existing records) - and that way I can just query on that one field?

Any thoughts/help is greatly appreciated!

Since you already have a type field, it could be a use case for STI, ie same SQL schema for the model but different behavior on the ruby side.

Note the "type" field may already be causing issues with rails that you may not have considered as this field generally is reserved specifically for Single Table Inheritance STI in rails.

If you use STI you could just write an accessor that pulls the correct field from the database and presents it for each model.

I think this approach should work assuming that no appointment should have a created_at before its start_on unless it is GLA

scope :last_appointment_from, ->(date, type) {
  query = joins(:appointments)
  query = query.where('GREATEST(appointments.start_on, appointments.created_at) = (
    SELECT GREATEST(MAX(start_on), MAX(created_at)) 
    FROM appointments
    WHERE appointments.property_id = properties.id)')
  query = query.where('GREATEST(appointments.start_on, appointments.created_at) >= ?', date)
  query
}

I'm not very good with Rails but for the pure MySQL you could use a where like this:

WHERE (
        (appointments.created_at > date
             AND appointments.type = 1)
        OR 
        (appointments.start_on > date
             AND appointments.type = 0)
      )

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM