> Player.joins(:game).order('games.scheduled_start ASC').last(5).sum(:ppg)
=> NoMethodError: undefined method `+' for #<GamePlayer:0x007ff543cd05d8>
> Player.joins(:game).order('games.scheduled_start ASC').sum(:ppg)
=> #<BigDecimal:7ff543cebc20,'0.30115E3',18(18)>
所以,我不明白为什么.last(n)
打破了我在此系列上调用.average
和.sum
的能力。
修改
[19] pry(main)> GamePlayer.order('id desc').limit(10).map{|x| x.ppg.to_f}
GamePlayer Load (0.6ms) SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 10
=> [14.0, 0.75, 1.2, 0.0, 2.55, 1.19, 2.04, 2.0, 0.0, 24.68]
[20] pry(main)> GamePlayer.order('id desc').limit(10).average(:ppg).to_f
(74.4ms) SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 10
=> 8.943831900603671
[21] pry(main)> GamePlayer.order('id desc').limit(50).average(:ppg).to_f
(73.4ms) SELECT AVG("game_players"."ppg") AS avg_id FROM "game_players" LIMIT 50
=> 8.943831900603671
[22] pry(main)> GamePlayer.order('id desc').limit(50).map{|x| x.ppg.to_f}.sum/50
GamePlayer Load (0.9ms) SELECT "game_players".* FROM "game_players" ORDER BY id desc LIMIT 50
=> 3.649800000000001
任何人都知道这种差异是什么?
答案 0 :(得分:4)
好last(5)
(或更一般地last(n)
)是Array
上定义的方法,这意味着您通过调用{{1}来构建ActiveRecord::Relation
}将被计算到一个数组,然后将在该结果数组上调用Player.joins(:game).order('games.scheduled_start ASC')
。
Rails增加了在数组上调用last(5)
的功能,但它的工作方式与sum
上的工作方式不同(通过在每个对象上调用ActiveRecord::Relation
和当前总和,以{开头{1}})。
相反,你可能想要使用它:
+
请注意,我已从0
切换到players = Player.joins(:game).order('games.scheduled_start DESC').limit(5)
sum = Player.joins(:game).where(id: players).sum(:ppg)
,因为限制始终会从一开始就采用元素。现在ASC
实际上将被转换为相应的SQL聚合函数,该函数将在DESC
- 列上运行。
需要sum
- 子句才能触发子查询,以确保:ppg
仅适用于where
选择的玩家。
如果您确实想使用数组(速度较慢),可以使用此方法:
sum
但limit
仅适用于players = Player.joins(:game).order('games.scheduled_start ASC').last(5)
# builds the sum of all ppg-values of all players selected
sum = players.sum(&:ppg)
,因为它未定义
average
(甚至不在Rails中)。当然,你可以自己构建它,但同样,你可以自己构建它
ActiveRecord::Relation
方法会更快。