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,在某些場景下可以大大減少對數據庫的查詢次數,提高頁面的執行效率。