Mysql
 sql >> Base de données >  >> RDS >> Mysql

Répertorier les utilisateurs disponibles à une certaine date

Voici une façon de le modéliser. Disons que nous avons un modèle "Engagement" qui a une date et une heure de début, une date et un nom de fin. Un engagement a de nombreux utilisateurs, via une autre table de jointure appelée "user_engagements" (avec le modèle UserEngagement correspondant). Nous avons donc

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

Nous avons maintenant un joli schéma simple. Un engagement modélise essentiellement quelque chose qui se passe, et user_engagements modélise les utilisateurs qui sont réservés pour faire cette chose. Nous partons du principe (non écrit dans le code) que lorsqu'ils font quelque chose, ils ne sont pas disponibles pour faire autre chose.

Notre tâche suivante consiste à écrire une méthode qui renvoie les utilisateurs disponibles dans un délai donné, c'est-à-dire un nouvel engagement. Donc, nous faisons un engagement et nous voulons que tous les utilisateurs qui n'ont pas d'engagement se croisent avec notre nouvel engagement. Je pense que la façon la plus simple de procéder pourrait être de trouver tous les utilisateurs qui ont un engagement croisé, puis de renvoyer tous les utilisateurs qui ne le sont pas. Si tu vois ce que je veux dire. Une façon plus précise de dire que e2 croise avec e1 est que e2 commence avant la fin de e1 ET se termine après le début de e1.

Faisons-en une méthode d'un objet d'engagement puisqu'il dépend totalement des données d'un engagement.

#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

J'ai l'impression qu'il existe un moyen plus efficace d'obtenir cela en une seule requête, mais je n'arrive pas à mettre le doigt sur le sql.