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

Rails 3.1 avec PostgreSQL :GROUP BY doit être utilisé dans une fonction d'agrégation

Le sql généré par l'expression n'est pas une requête valide, vous regroupez par user_id et en sélectionnant de nombreux autres champs en fonction de cela, mais sans indiquer à la base de données comment elle doit agréger les autres champs. Par exemple, si vos données ressemblent à ceci :

a  | b
---|---
1  | 1
1  | 2
2  | 3

Maintenant, lorsque vous demandez à db de grouper par a et renvoie également b, il ne sait pas comment agréger les valeurs 1,2 . Vous devez indiquer s'il doit sélectionner min, max, moyenne, somme ou autre chose. Juste au moment où j'écrivais la réponse, il y a eu deux réponses qui pourraient mieux expliquer tout cela.

Dans votre cas d'utilisation cependant, je pense que vous ne voulez pas un groupe au niveau de la base de données. Comme il n'y a que 10 arts, vous pouvez les regrouper dans votre application. N'utilisez pas cette méthode avec des milliers d'arts :

 arts = Art.all(:order => "created_at desc", :limit => 10)
 grouped_arts = arts.group_by {|art| art.user_id}
 # now you have a hash with following structure in grouped_arts
 # { 
 #    user_id1 => [art1, art4],
 #    user_id2 => [art3],
 #    user_id3 => [art5],
 #    ....
 # }

MODIF : Sélectionnez latest_arts, mais un seul art par utilisateur

Juste pour vous donner une idée de sql (je ne l'ai pas testé car je n'ai pas de RDBMS installé sur mon système)

SELECT arts.* FROM arts
WHERE (arts.user_id, arts.created_at) IN 
  (SELECT user_id, MAX(created_at) FROM arts
     GROUP BY user_id
     ORDER BY MAX(created_at) DESC
     LIMIT 10)
ORDER BY created_at DESC
LIMIT 10

Cette solution est basée sur l'hypothèse pratique selon laquelle deux arts pour le même utilisateur ne peuvent pas avoir le même created_at le plus élevé, mais cela peut très bien être faux si vous importez ou créez par programmation une grande quantité d'arts. Si l'hypothèse n'est pas vraie, le sql pourrait devenir plus artificiel.

MODIF : Essayez de changer la requête en Arel :

Art.where("(arts.user_id, arts.created_at) IN 
             (SELECT user_id, MAX(created_at) FROM arts
                GROUP BY user_id
                ORDER BY MAX(created_at) DESC
                LIMIT 10)").
    order("created_at DESC").
    page(params[:page]).
    per(params[:per])