2010-04-23 11 views
5

Estoy tratando de usar Heroku y aparentemente Postgresql es mucho más estricto que SQL para funciones de agregado. Cuando presiono a Heroku recibo un error que dice lo siguiente.Agregar columnas de tabla a una cláusula Group by - Ruby on Rails - Postgresql

On another question Pedí que recibiera algunas indicaciones que dijeran que debería agregar las columnas a mi grupo por cláusula y no estoy seguro de cómo hacerlo. Consulte el error completo a continuación y el índice PostsControll #.

SELECT posts.*, count(*) as vote_total FROM "posts" INNER JOIN "votes" ON votes.post_id = posts.id GROUP BY votes.post_id ORDER BY created_at DESC LIMIT 5 OFFSET 0): 

PostsController

def index 
    @tag_counts = Tag.count(:group => :tag_name, 
     :order => 'count_all DESC', :limit => 20) 
     conditions, joins = {}, :votes 

    @ugtag_counts = Ugtag.count(:group => :ugctag_name, 
     :order => 'count_all DESC', :limit => 20) 
     conditions, joins = {}, :votes 

    @vote_counts = Vote.count(:group => :post_title, 
      :order => 'count_all DESC', :limit => 20) 
      conditions, joins = {}, :votes 


     unless(params[:tag_name] || "").empty? 
     conditions = ["tags.tag_name = ? ", params[:tag_name]] 
     joins = [:tags, :votes] 
     end 
     @posts=Post.paginate(
       :select => "posts.*, count(*) as vote_total", 
       :joins => joins, 
       :conditions=> conditions, 
       :group => "votes.post_id", 
       :order => "created_at DESC", 
       :page => params[:page], :per_page => 5) 
     @popular_posts=Post.paginate(
       :select => "posts.*, count(*) as vote_total", 
       :joins => joins, 
       :conditions=> conditions, 
       :group => "votes.post_id", 
       :order => "vote_total DESC", 
       :page => params[:page], :per_page => 3) 

    respond_to do |format| 
     format.html # index.html.erb 
     format.xml { render :xml => @posts } 
     format.json { render :json => @posts } 
     format.atom 
    end 
    end 

Respuesta

3

MySQL y SQLite son tan flexibles que permiten columnas en la lista de selección sin ser nombradas en la cláusula GROUP BY (y no dentro de una función agregada como COUNT()). Pero este nivel de flexibilidad puede conducir a consultas ambiguas.

PostgreSQL es solo tan estricto como el estándar ANSI SQL. Todas las otras bases de datos que he probado (Oracle, Microsoft, IBM DB2, Firebird) se comportan como PostgreSQL en este tema.

Lo que debe hacer es hacer que la lista de columnas posts en su lista de selección coincida con las columnas nombradas en su cláusula GROUP BY. Haga esto seleccionando menos columnas o agregando columnas al :group.

No soy un experto en Rails, y no puedo encontrar un ejemplo de cómo pasar varias columnas como argumento a :group. Mirando el código para active_record/base.rb, parece que simplemente copia el valor de la opción en una cláusula literal de SQL GROUP BY. Así que yo supongo (sin haber probado) que usted puede hacer esto:

... 
:group => "posts.post_id, posts.foo, posts.bar, posts.baz", 
... 

Tenga en cuenta que usted tiene que nombrar cada columna que tiene en su selecta lista que no es parte de una función agregada.

+0

Eso lo hizo. Muchas gracias. A punto de publicar el próximo número como una pregunta separada. – bgadoci

+0

Siempre he usado una cadena simple para enumerar las columnas que se agrupan. –

1

has necesitado acaba de cambiar a usar por ejemplo posts.id:

SELECT posts.*, count(*) as vote_total FROM "posts" INNER JOIN "votes" ON votes.post_id = posts.id GROUP BY posts.id ORDER BY created_at DESC LIMIT 5 OFFSET 0); 

Si es así, ¿cómo el conjunto de resultados a continuación difieren de lo que está recibiendo con tu SQL existente?

+0

Intenté simplemente cambiar el: group => "votes.post_id" para publicar la identificación, pero al hacer clic en ese grupo y enviar la URL w/tag_name, se rompe. Aquí está el error: SQLite3 :: SQLException: nombre de columna ambiguo: post_id: SELECT posts. *, Count (*) como vote_total FROM "posts" INNER JOIN "tags" ON tags.post_id = posts.id INNER JOIN "votos" ON votes.post_id = posts.id WHERE (tags.tag_name = 'mostest recent tag') GROUP BY post_id ORDER BY created_at DESC LIMIT 5 OFFSET 0 – bgadoci

+0

aha - bueno ese error te dice que no puede decir si estás agrupando por votes.post_id o tags.post_id Entonces, tiene que decirlo :) –

+0

Esto todavía no funciona en PostgreSQL. Funcionará en PostgreSQL 9.1 si posts.id es la clave principal. –

0

Sólo estaba tratando con este problema en los carriles 3. Aquí está la solución que se me ocurrió:

group_models = [Post, Vote, etc.] 
group_columns = ['"votes"."post_id"'] # whatever column you were specifying with :group 
group_models.each do |model| 
    group_columns += model.column_names.map { |col| "\"#{model.table_name}\".\"#{col.name}\"" } 
end 
Post.where(whatever...).group(group_columns) 
1

me ocurrió con una variación que consiste en la creación del nombre de la tabla se unen a los demonios de forma dinámica en lugar de en tiempo de compilación

model_columns = Model.column_names.collect do |c| "#{Model.table_name}.#{c}" end.join(",")

Cuestiones relacionadas