Incorporating Custom SELECT clause in ActiveRecord query

早过忘川 提交于 2020-02-03 02:05:48

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!