使用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执行计算本身要慢,如接受的答案中所述。