2010-04-23 74 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(",")