新手问题 Active Record: 資料表操作里的 group 应该怎么选择性获取

QueXuQ · 2013年01月30日 · 最后由 tumayun 回复于 2013年02月04日 · 2662 次阅读

如果有下面的一个表:

id  |   name  |    price   | number |
1   |    乌龟  |     30     |   1   |
2   |    猫    |      10    |    2   |
3   |    乌龟  |      20    |   1   |
4   |    乌龟  |     -10    |   1   |
5   |    猫    |      20    |    1   |
6   |    猫    |      30    |   1    |

我想通过 group,变成下面的表:

id  |   name   |    price   | number |
4   |    乌龟  |     20     |   3   |
6   |    猫    |      30    |   4  |

通过以下的语句:

where("price > ?", 0).group("name")

也就是说,我要 group,name,但是 price 想要获取 id 最大的那个,而且 price 不要<0 的,可是加 order 也没有反应,请问通过什么办法可以塞选到我想要的表呢?还有那个 number 得出个分组的总和。

方法一(会执行两条 SQL 语句):

Animal.where(id: Animal.select('max(id) as id').where('price > 0').group(:name).pluck(:id))

方法二(一条 SQL):

Animal.find_by_sql('select b.* from (select max(id) as id from animals where price > 0 group by name) a inner join animals b on (a.id = b.id)')

#1 楼 @xhh 貌似还是不可以

`id` IN (10, 3)

他选 3 了,明明 11 还有。

#1 楼 @xhh 这句似乎没有什么作用.select('max(id) as id')

#1 楼 @xhh 谢谢,原来问题在select('max(id) as id')不可以两个都是 id,我用select('max(id) as max_id')替换了就可以了。 请问如果后面加个 number 的求和,又在你原本语句的基础上怎么设计好呢?

得到 price > 0 的计数:

Animal.select('max(id) as id, name, sum(number) as number').where('price > 0').group(:name)
# => [#<Animal id: 3, name: "乌龟", number: 2>, #<Animal id: 6, name: "猫", number: 4>] 

如果要得到所有的计数(不限制 price),应该需要分开做:

animals = Animal.select('max(id) as id, name').where('price > 0').group(:name)
# => [#<Animal id: 3, name: "乌龟">, #<Animal id: 6, name: "猫">] 

numbers = Animal.group(:name).sum(:number)
# => {"乌龟"=>3, "猫"=>4} 

animals.each { |animal| animal.number = numbers[animal.name] }
# => [#<Animal id: 3, name: "乌龟", number: 3>, #<Animal id: 6, name: "猫", number: 4>]

干嘛不用 having 啊?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号