PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Rails 3.1 com PostgreSQL:GROUP BY deve ser usado em uma função agregada


O sql gerado pela expressão não é uma consulta válida, você está agrupando por user_id e selecionando muitos outros campos com base nisso, mas não informando ao banco de dados como ele deve agregar os outros campos. Por exemplo, se seus dados estiverem assim:
a  | b
---|---
1  | 1
1  | 2
2  | 3

Agora, quando você pede ao db para agrupar por a e também retorna b, não sabe agregar valores 1,2 . Você precisa saber se precisa selecionar min, max, average, sum ou outra coisa. Assim como eu estava escrevendo a resposta, houve duas respostas que podem explicar tudo isso melhor.

No seu caso de uso, porém, acho que você não deseja um grupo no nível do db. Como são apenas 10 artes, você pode agrupá-las em seu aplicativo. Não use este método com milhares de artes:
 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],
 #    ....
 # }

EDITAR: Selecione as últimas_arts, mas apenas uma arte por usuário

Só para dar uma ideia do sql (não testei pois não tenho RDBMS instalado no meu sistema)
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

Esta solução é baseada na suposição prática de que duas artes para o mesmo usuário não podem ter o mesmo valor criado_at, mas pode estar errado se você estiver importando ou criando programaticamente uma grande quantidade de artes. Se a suposição não for verdadeira, o sql pode ficar mais artificial.

EDITAR: Tente alterar a consulta para 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])