sql >> Base de Datos >  >> RDS >> Mysql

Listado de usuarios disponibles en una fecha determinada

Aquí hay una forma de modelarlo. Digamos que tenemos un modelo 'Compromiso' que tiene una fecha y hora de inicio, una fecha y hora de finalización y un nombre. Un compromiso tiene muchos usuarios, a través de otra tabla de unión llamada 'user_engagements' (con el modelo UserEngagement correspondiente). Entonces tenemos

User
  has_many :user_engagements
  has_many :engagements, :through => :user_engagements

Engagement
  #fields - starts_at, ends_at (both datetime)
  has_many :user_engagements
  has_many :users, :through => :user_engagements

UserEngagement
  belongs_to :user
  belongs_to :engagement

Ahora tenemos un bonito esquema simple. Un compromiso básicamente modela algo que está sucediendo, y user_engagements modela a los usuarios que están reservados para hacer eso. Suponemos (no está escrito en el código) que cuando están haciendo algo, no están disponibles para hacer nada más.

Nuestra próxima tarea es escribir un método que devuelva a los usuarios disponibles dentro de un período de tiempo determinado, es decir, un nuevo compromiso. Entonces, hacemos un compromiso y queremos que todos los usuarios que no tienen un compromiso se crucen con nuestro nuevo compromiso. Creo que la forma más sencilla de hacer esto podría ser encontrar a todos los usuarios que tienen un compromiso cruzado y luego devolver a todos los usuarios que no son ellos. Si sabes a lo que me refiero. Una forma más precisa de decir que e2 se cruza con e1 es que e2 comienza antes del final de e1 Y termina después del inicio de e1.

Hagamos de esto un método de un objeto de compromiso, ya que depende totalmente de los datos de un compromiso.

#in Engagement
def unavailable_user_ids
  User.find(:all, :include => [:user_engagements], :select => "users.id", :conditions => ["user_engagements.starts_at < ? and user_engagements.ends_at > ?", self.ends_at, self.starts_at]).collect(&:id)
end

def available_users
  User.find(:all, :conditions => ["id not in (?)", self.unavailable_user_ids])
end

Siento que hay una forma más eficiente de obtener esto en una sola consulta, pero no puedo identificar el sql.