使用Activerecord对多列进行求和
我是Activerecord的新手。 我想对模型学生的多个列进行求和。 我的模范学生如下:
class Student < ActiveRecord::Base attr_accessible :class, :roll_num, :total_mark, :marks_obtained, :section end
我想要这样的东西:
total_marks, total_marks_obtained = Student.where(:id=>student_id).sum(:total_mark, :marks_obtained)
但它给出了以下错误。
NoMethodError: undefined method `except' for :marks_obtained:Symbol
所以我问我是否必须为上述模型查询两次,即一次查找总标记,另一次查找获得的标记。
如果需要,可以使用原始SQL。 像这样返回一个你必须提取值的对象……我知道你指定了活动记录!
Student.select("SUM(students.total_mark) AS total_mark, SUM(students.marks_obtained) AS marks obtained").where(:id=>student_id)
对于rails 4.2(之前未选中)
Student.select("SUM(students.total_mark) AS total_mark, SUM(students.marks_obtained) AS marks obtained").where(:id=>student_id)[0]
注意声明后面的括号。 没有它,语句将返回Class :: ActiveRecord_Relation,而不是AR实例。 对此有重要意义的是,您不能first
使用该关系。
....where(:id=>student_id).first #=> PG::GroupingError: ERROR: column "students.id" must appear in the GROUP BY clause or be used in an aggregate function
您可以使用pluck直接获得总和:
Student.where(id: student_id).pluck('SUM(total_mark)', 'SUM(marks_obtained)') # SELECT SUM(total_mark), SUM(marks_obtained) FROM students WHERE id = ?
您可以将所需的列或计算字段添加到pluck
方法,它将返回包含值的数组。
如果你只想要总和列total_marks和marks_obtained,试试这个
Student.where(:id=>student_id).sum('total_mark + marks_obtained')
另一种方法是ActiveRecord::Calculations.pluck
然后是外部数组上的Enumerable#sum
,再次是内部数组对:
Student .where(id: student_id) .pluck(:total_mark, :marks_obtained) .map(&:sum) .sum
生成的SQL查询很简单:
SELECT "students"."total_mark", "students"."marks_obtained" FROM "students" WHERE "students"."id" = $1
pluck
的初始结果将是一个数组对数组,例如:
[[10, 5], [9, 2]]
.map(&:sum)
将在每对上运行sum
,总计该对并展平数组:
[15, 11]
最后,扁平数组上的.sum
将产生单个值。
编辑:
请注意,虽然只有一个查询,但您的数据库将为where
匹配的每个记录返回结果行。 这个方法使用ruby来进行总计,所以如果有很多记录(即数千个),这可能比SQL执行计算本身要慢,如接受的答案中所述。