Description
When using MySQL, .group and .having can be used to accomplish the very common task of finding records from SQL table table_a by specifying some conditions on some tables joining table_a, i.e. table_b, table_c etc. So, if I want to find all the users that have paid more then four times, I can do:
User.joins(:payments).group('users.id').having('count(payments.id) > 4')
This however doesn't work with PostgreSQL, which will in this case throw an error message similar to this one:
ActiveRecord::StatementInvalid: PGError: ERROR: column "users.email" must
appear in the GROUP BY clause or be used in an aggregate function
This is because in PostgreSQL the columns that appear in the FROM clause have to be the same ones that appear in the GROUP by clause. Correct me if I'm wrong, but from what I see you can fix it only by using .select('users.id,users.email,..."), but in this case you either have to manually list all the columns or you get crippled objects returned with only some attributes present. This forces PostgreSQL users to either come up with some ugly workarounds or to use find_by_sql for any but the simplest queries concerning only one table. I don't know what's the most "Railsy" way of fixing it, but I think it would at least be helpful to have a method that would return all the column names qualified by the table name, like this:
module ActiveRecord
class Base
def all_columns
column_names.collect { |c| "#{table_name}.#{c}" }.join(",")
end
end
end
That would make .group and .having usable in PostgreSQL like this:
User.joins(:payments).group(User.all_columns).having('count(payments.id) > 4')
In the end I think it would be great if Rails provided some shorthand notation for doing the same thing, like this:
User.joins(:payments).group(:users).having('count(payments.id) > 4')
Edit:
Maybe .group with no arguments could do just that?