2 votes

Rails et ActiveRecord : Requête SQL difficile

Dans mon application Rails, j'autorise les utilisateurs à "v

J'essaie de construire une requête qui rend tous les événements que soit A) un utilisateur a no voté sur OU B) les événements en cours sur lesquels un utilisateur a voté sur Il y a un mois.

L'événement possède une colonne booléenne "en cours". L'événement a_beaucoup de votes. Et User a_nombreux votes.

Voici ma requête pour obtenir tous les événements d'un utilisateur no voté. Cela fonctionne.

scope :unvoted, ->(user_id) {
    joins(
         "LEFT OUTER JOIN votes ON votes.event_id = events.id AND " +
         "votes.user_id = #{user_id}"
         ).where("votes.id IS NULL")
    }

J'essaie d'ajouter le ou partie de la requête. J'ai besoin d'inclure les événements "en cours" pour lesquels l'utilisateur a voté il y a plus d'un mois. Voici ce que j'ai essayé :

scope :unvoted, ->(user_id) {
    joins(
          "LEFT OUTER JOIN votes ON votes.event_id = events.id AND " +
          "votes.user_id = #{user_id}"
         )
         .where(
                 "votes.id IS NULL OR events.ongoing = ? AND MAX(votes.created_at) < ?", true, 1.month.ago
          )
  }

Mais cela me donne l'erreur :

PG::GroupingError : ERROR : les fonctions d'agrégation ne sont pas autorisées dans WHERE

Alors j'ai essayé ça :

scope :unvoted, ->(user_id) {
    joins(
          "LEFT OUTER JOIN votes ON votes.event_id = events.id AND " +
          "votes.user_id = #{user_id}"
                            ).
   having('votes.id IS NULL OR events.ongoing = ? AND MAX("votes"."created_at") < ?', true, 1.month.ago).
   group("events.id")
  }

Mais cela me donne l'erreur :

ERREUR : la colonne doit apparaître dans la clause GROUP BY ou être utilisée dans une fonction d'agrégation.

Quelle est la requête appropriée que je recherche ?

0voto

Abhishek Kumar Points 445

EDIT : Il semble qu'il n'y ait aucun moyen d'écrire OR avec HAVING. Vous pouvez utiliser une sous-requête( Utiliser 'OR' entre les clauses HAVING et WHERE dans MySQL ? ) ou UNION pour résoudre ce problème.

Ou, pour simplifier les choses, vous pouvez les diviser en deux requêtes.

seule solution ActiveRecord : https://stackoverflow.com/a/15413611/5213979

0voto

Nikhil Points 614

Pouvez-vous essayer

scope :unvoted, ->(user_id) {
    joins(
      "LEFT OUTER JOIN votes ON votes.event_id = events.id AND " +
      "votes.user_id = #{user_id}"
    ).where(
      "votes.id IS NULL OR events.ongoing = ?", true                      
    ).select('events.*, MAX(votes.created_at) as created_at')
    ).group('events.id')
}

et ensuite dans votre méthode, vous pouvez faire

Event.unvoted.select{|e| e.created_at < 1.month.ago}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X