2010-04-23 73 views
5

我想使用Heroku,显然Postgresql比SQL对集合函数更严格。当我推到Heroku时,我收到一个错误,指出下面的内容。将表列添加到group by子句 - Ruby on Rails - Postgresql

On another question我问我收到了一些指导,说我应该将列添加到我的group by子句中,但我不知道该怎么做。请参阅下面的完整错误和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 

回答

3

MySQL和SQLite非常灵活,它们允许选择列表中的列没有在GROUP BY子句中命名(而不在COUNT()之类的集合函数中)。但是这种灵活性会导致模糊的查询。

PostgreSQL只与ANSI SQL标准一样严格。我测试过的所有其他数据库(Oracle,Microsoft,IBM DB2,Firebird)在这个问题上的行为与PostgreSQL相似。

您需要做的是使您的选择列表中的posts列的列表与GROUP BY子句中指定的列匹配。通过选择较少的列或通过向:group添加列来执行此操作。

我不是Rails专家,我找不到一个如何将多列作为参数传递给:group的示例。查看active_record/base.rb的代码,看起来它只是将选项值复制到文字SQL GROUP BY子句中。所以,我想(没有尝试过它),你可以这样做:

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

请注意,您必须命名列在您的选择列表是一个非集合函数的一部分有。

+0

这样做。非常感谢。下一期将作为单独问题发布。 – bgadoci 2010-04-23 22:16:00

+0

我一直使用一个简单的字符串来列出被分组的列。 – 2011-01-03 09:00:43

1

您是否尝试过刚刚切换到使用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); 

如果是这样,如何将结果集然后从你得到什么区别与你现有的SQL?

+0

我试着改变:group =>“votes.post_id”以发布ID,但当点击该组并发送URL w/tag_name时,它会中断。这里是错误:SQLite3 :: SQLException:模棱两可的列名:post_id:SELECT posts。*,count(*)as vote_total FROM“posts”INNER JOIN“tags”ON tags.post_id = posts.id INNER JOIN“votes”ON votes.post_id = posts.id WHERE(tags.tag_name ='mostest最近的标记')GROUP BY post_id ORDER BY created_at DESC LIMIT 5 OFFSET 0 – bgadoci 2010-04-23 15:59:46

+0

aha - 那么错误是告诉你,它不能告诉你是否由votes.post_id或tags.post_id 所以 - 你必须告诉它:) – 2010-04-26 16:23:01

+0

这仍然不能在PostgreSQL中工作。如果posts.id是主键,它将在PostgreSQL 9.1中工作。 – 2011-01-03 13:11:03

0

我只是应付on Rails的3.这个问题这是我想出了一个解决方案:

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

我想出了,涉及创建表的名称在编译时加入恶魔动态,而不是变化

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