skyeagle / nested_set

Rails 3 support! An awesome replacement for acts_as_nested_set and better_nested_set.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Group By in SQL is incorrect syntax

demersus opened this issue · comments

I was experiencing a problem with the rebuild! method for my tree which uses as scope. My scope is on a column named 'listing_type_id'.

Here is the message:

PGError: ERROR:  column "categories.id" must appear in the GROUP BY clause or be used in an aggregate function: SELECT     "categories".* FROM       "categories"  WHERE ("categories"."parent_id" IS NULL) GROUP BY listing_type_id ORDER BY  "lft"

It appears to be a problem with the all_roots_valid? method:

def all_roots_valid?
    if acts_as_nested_set_options[:scope]
      roots.group(scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots|
        each_root_valid?(grouped_roots)
      end
    else
      each_root_valid?(roots)
    end
  end

I am not exactly sure why it needs a group() scope added. I removed it by overriding the method in my model and it works fine now:

def self.all_roots_valid?
    if acts_as_nested_set_options[:scope]
      roots.group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots|
        each_root_valid?(grouped_roots)
      end
    else
      each_root_valid?(roots)
    end
  end

That is postgres specific group query issue. In general all_roots_valid? method was bad written. Needs more time for investigation.

This message is valid for any sql based database. Selected columns must appear in the group by statement, or an aggregate function. Anyway, it looks like you are doing the grouping in ruby after the records are fetched. Which would make the sql: GROUP BY redundant.

Gouping logic should be into the sql but it's not trivial for the postgres in that case. Otherwise you have got many thousand instances of objects on that method for big tree.

I would agree. It should take less time in sql than in ruby. However, what I am hinting at, is that the syntax is incorrect. Even if you are using mysql or some other database. It is not just a postgres issue. I just happened to be using postgres when I found the error.

The method was already calling the ruby group_by method. So to remedy, I just removed the arel/activemodel method call for group() from this method because it was generating incorrect sql syntax.

Perhaps a better solution would be to rewrite the method so that it utilizes the database better instead of using ruby group_by. I will take a stab at it and let you know when I have a pull request if you are interested. Thanks, everything else about this gem is wonderful! ;-)

Yes, rewriting method is what i mean. It will be greate if you do it with tests in the pull request. You are welcome :-)

I will try to rewrite it and write some tests. But for now, you may want to apply the code I posted here. As is, the method is unusable with a scope until you remove the group() statement. The performance may not be ideal with large trees, but at least it will work.

Also, for pg you should use select distinct on (field) instead of group by.
To check adapter type use:

case PagePart.connection.adapter_name.downcase
when 'postgresql' then