问题
I have a large table of assessments, in that table there are several integer columns with numerical scores. I am trying to remove some N+1 iteration to speed up my application.
I can generate this query in raw SQL to gather all of the scores
query =
'SELECT ' +
Assessment.rating_attributes.collect{|attribute|
1.upto(5).collect do |i|
%Q{SUM(CASE WHEN #{attribute.to_s} = #{i} then 1 else 0 end) as #{attribute}_score_#{i}}
end
}.join(', ') + ' FROM assessments'
When I execute this query with:
$> ActiveRecord::Base.connection.execute(query)
=> #<PG::Result:0x007fc9e7e541e8 status=PGRES_TUPLES_OK ntuples=1 nfields=55 cmd_tuples=1>
I get the correct result:
ActiveRecord::Base.connection.execute(query).first.values
=> ["2400", "458", "3343", "1021", "93", "2352", "455", "3119", "1174", "150", "2378", "357", "2976", "1357", "181", "2042", "258", "3024", "1646", "280", "1274", "193", "3907", "1704", "172", "799", "93", "4593", "1670", "95", "1759", "361", "2542", "947", "69", "21", "100", "81", "42", "38", "8", "32", "51", "78", "112", "19", "119", "72", "43", "29", "0", "0", "0", "0", "0"]
I would like to perform this same query, but not across the entire table. I'd like to be able to chain it into an activerecord query, e.g.:
Assessment.where(selection_attribute: 1038).select(query_without_select_keyword_or_from_clause)
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column "assessments.id" must appear in the GROUP BY clause or be used in an aggregate function
and have it give me the same kind of result, but on the subset. My naive efforts (e.g. the .select(query) call in my example) have failed, and I'm not even sure how to approach this.
I've hit a wall, and I'd appreciate any guidance, even on how to craft a search for a solution. Thank you.
回答1:
Well, this was simple. Using .first
was the issue. I suppose this is because there are no model records returned by the query. If I address the 0 index of the result directly, I get all of my scores.
so this code works:
query =
Assessment.rating_attributes.collect{|attribute|
1.upto(5).collect do |i|
%Q{sum(CASE WHEN #{attribute.to_s} = #{i} then 1 else 0 end) as #{attribute}_score_#{i}}
end
}.join(', ')
Assessment.where(selection_attribute: 1038).select(query)[0]
=> #<Assessment id: nil>
Assessment.where(selection_attribute: 1038).select(query)[0].first_attribute_score_1
=> 3
来源:https://stackoverflow.com/questions/29477824/incorporating-custom-select-clause-in-activerecord-query