group by是关系型数据库中较为常用的方法,rails也提供了类似的group_by方法,但两者还是有不小区别的,下面我们通过一个实例说明一下:
有一张表: orders,包含这些字段,
用户ID: user_id
商品ID: product_id
购买数量: amount
购买时间: buy_at
user_id | product_id | amount | buy_at |
---|---|---|---|
1 | 1 | 3 | 2015-05-05 |
1 | 2 | 4 | 2015-05-05 |
2 | 1 | 5 | 2015-05-05 |
2 | 2 | 6 | 2015-05-06 |
先简单说一下数据库中group by的用法,顾名思义,就是分组的意思。使用了group by,那SQL语句的select部分,只能写sum或者count这类函数(只有被group by的字段可以直接取),因为数据库已经把所有记录按照指定条件进行了分组,每组其实就是一条记录(由符合该组条件的一条或者多条数据转变而来),比如:
select user_id, sum(amount) from orders group by user_id
此时得到的结果就是:
user_id | amount |
---|---|
1 | 7 |
2 | 11 |
在使用group by之前,可以正常使用where来对需要group by的数据进行预筛选,如果还需要对group by之后的数据再次进行筛选,可以在group by 之后使用having:
select user_id, sum(amount) as total_amount from orders where amount >=4 group by user_id having total_amount >=8
这句句子很好理解,先从全部四条数据中,选出购买数量大于等于4的订单(第一条数据被去掉了),然后按照上面的方法进行分组,分组后结果显示是:
user_id | amount |
---|---|
1 | 4 |
2 | 11 |
最后再次筛选出购买总数大于等于8的数据,那分组结果中的第一条数据又被去掉了,符合条件的只剩第二条了
如果用rails的find_by_sql来取数据:
@orders = Order.find_by_sql(["select user_id, sum(amount) from orders group by user_id"])
此时如果看@orders.size的话,应该是2,只有两条数据
这个时候,我们再看一下rails提供的order_by方法:
@orders = Order.all.group_by{|o|o.user_id}
此时我们得到的结果是这样的:
{1=>[#<Order id: 1, user_id: 1, product_id: 1, amount: 3, buy_at: 2015-05-05>, #<Order id: 2, user_id: 1, product_id: 2, amount: 4, buy_at: 2015-05-05>], 2=>[#<Order id: 3, user_id: 2, product_id: 1, amount: 5, buy_at: 2015-05-05>, #<Order id: 4, user_id: 2, product_id: 2, amount: 6, buy_at: 2015-05-06>]}
结果很明显,返回了一组Hash,key是user_id,value是等于这个user_id的所有实例对象,个人认为rails中的group_by,更符合“分组”这个词的本义,并没有去合并或者计算数据,而且根据要求进行了单纯的分组处理。我们拿第一条数据来看一下:
@orders.first
1=>[#<Order id: 1, user_id: 1, product_id: 1, amount: 3, buy_at: 2015-05-05>, #<Order id: 2, user_id: 1, product_id: 2, amount: 4, buy_at: 2015-05-05>]
@orders.first[0]
3
@orders.first[1]
[#<Order id: 1, user_id: 1, product_id: 1, amount: 3, buy_at: 2015-05-05>, #<Order id: 2, user_id: 1, product_id: 2, amount: 4, buy_at: 2015-05-05>]
此时又能对@orders.first[1]进行.each来迭代输出数据了
总结一下:两种group by,不存在好与坏,因为应用的场景不同,善于利用group by,在某些场景下可以大大减少对数据库的查询次数,提高页面的执行效率。