web-dev-qa-db-fra.com

GroupingError: ERROR: la colonne doit apparaître dans la clause GROUP BY ou être utilisée dans une fonction d'agrégat

J'ai dans mon contrôleur un code qui classe les albums en fonction de la note moyenne la plus élevée (code utilisé dans cette solution Comment afficher les albums les mieux notés via une relation has_many reviews ): 

@albums = Album.joins(:reviews).select("*, avg(reviews.rating) as average_rating").group("albums.id").order("average_rating DESC")

Ce code fonctionne parfaitement dans mon environnement de développement (sqlite3). Cependant, lorsque j'ai transmis le code à heroku et à postgresql, j'ai obtenu cette erreur: 

PG::GroupingError: ERROR:  column "reviews.id" must appear in the GROUP BY clause or be used in an aggregate function

Je me rends compte que c'est un problème assez courant, je suis un peu inexpérimenté avec SQL et j'ai donc du mal à refactoriser le code afin que cela fonctionne dans les environnements de développement et de production. 

26
Reuben

Vous n'êtes pas autorisé à sélectionner reviews.id (sélectionné implicitement via le caractère générique *) sans l'ajouter à la clause GROUP BY ni appliquer une fonction d'agrégation telle que avg(). La solution consiste à effectuer l'une des opérations suivantes:

  1. Supprimer le caractère générique * de votre sélection
  2. Ajoutez le champ reviews.id à votre clause de groupe
  3. Sélectionnez reviews.id explicitement et appliquez-lui une fonction d'agrégat (par exemple, sum(reviews.id)
  4. Remplacez le caractère générique * par le caractère générique propre à la table albums.*

La deuxième et la troisième option n’ont pas beaucoup de sens dans votre scénario cependant… .. Sur la base de votre commentaire, j’ai ajouté l’option quatre.

28
slash

Je voudrais juste partager ce code sur Ruby en utilisant un enregistrement actif (sinatra)

Je devais ajouter "group by" à une fonction "order by", donc ligne de code ...

de:

@models = Port.all.order('number asc')

à:

@models = Port.select(:id, :device_id, :number, :value, :sensor, :UOM).all.order('number asc').group(:id,:sensor,:UOM)

et cela a fonctionné parfaitement, rappelez-vous simplement que le champ ID dans ce cas, "Port.id" doit être ajouté à la clause group sinon cette erreur sera générée, et comme @slash l'a mentionné, vous ne pouvez pas y parvenir avec des fonctions spéciales (sélectionnez implicitement dans le caractère générique. * ou dans mon cas en utilisant "tous")

1
d1jhoni1b

La seule solution vraiment acceptable que j'ai trouvée à ce genre de problème était avec ce code:

@albums = Album.joins(:reviews).select("*, avg(reviews.rating) as average_rating").group_by(&:id).order("average_rating DESC")

J'espère que ça aide quelqu'un.

0
Weengs