2012-08-23 86 views
5

用戶按年齡我想按年齡範圍列出用戶數:集團紅寶石

Range : #Users 
10-14 : 16 
15-21 : 120 
22-29 : 312 
30-40 : 12131 
41-70 : 612 
71-120 : 20 

我想創建散列的靜態數組:

AGE_RANGES = [ 
    {label:"10 - 14", min:10, max:14}, 
    {label:"15 - 21", min:15, max:21}, 
    {label:"22 - 29", min:22, max:29}, 
    {label:"30 - 40", min:30, max:40}, 
    {label:"41 - 70", min:41, max:70}, 
    {label:"71 - 120", min:71, max:120} 
] 

然後將其用於我的搜索過濾器以及我的查詢。但是,我想不出一種從中獲得最高性能的方法。

我在我的模型方法只按年齡組:

def self.group_by_ageRange(minAge, maxAge) 

    query = User.group("users.age") 
       .where("users.age BETWEEN minAge and maxAge ") 
       .select("users.age, 
         count(*) as number_of_users") 

end 

有什麼建議?

+1

http://stackoverflow.com/questions/232387/in-sql-how-can-you-group-by-in-ranges – InternetSeriousBusiness

回答

7

你想建立一些SQL,看起來像這樣:

select count(*), 
     case 
      when age between 10 and 14 then '10 - 14' 
      when age between 15 and 21 then '15 - 21' 
      -- ... 
     end as age_range 
from users 
where age between 10 and 120 
group by age_range 

在ActiveRecord的條款,這將是:

# First build the big ugly CASE, we can also figure out the 
# overall max and min ages along the way. 
min = nil 
max = nil 
cases = AGE_RANGES.map do |r| 
    min = [r[:min], min || r[:min]].min 
    max = [r[:max], max || r[:max]].max 
    "when age between #{r[:min]} and #{r[:max]} then '#{r[:min]} - #{r[:max]}'" 
end 

# Then away we go... 
age_ranges = Users.select("count(*) as n, case #{cases.join(' ')} end as age_range") 
        .where(:age => min .. max) 
        .group('age_range') 
        .all 

,將讓你有對象的數組中age_ranges和那些對象將有nage_range方法。如果你想要一個散列,那麼:

age_ranges = Hash[age_ranges.map { |r| [r.age_range, r.n] }] 

這不包括當然沒有任何人的範圍;我將把它作爲讀者的練習。

+0

這解決了我的問題,謝謝。我現在似乎在控制器內部有一些軌道錯誤...如果我添加'logger.debug(「項目:#{@ ageRange_items.inspect}」)'它一切正常......如果沒有,它只是設置('')'爲'age_range',給出了一個自然的錯誤,說'列age_range不存在' – MrWater

+0

@itsalltime:這很難診斷,沒有看到最終的代碼。 –

+0

這裏它去...它比我發佈的問題複雜一點,因爲它有鏈接,但它不應該有這種行爲'query = User.joins(stores:{receipts:{tag::user} (「users.id =:user_id」)) .select(「 ,user_id:user) .where(「users_tags.age」=> min .. max) 。group(「age_range」)' – MrWater

0

我發現接受的答案有點密集。快速但很難理解和寫作。今天,我想出了一個更慢,但更簡單的解決方案。由於我們將年齡分組爲範圍,因此我們可以假設我們不會有values over 125

這意味着如果您對分組和計數結果集使用ruby過濾器,則不會迭代超過125個項目。這將比基於sql範圍的組/數更慢,但對於我的目的來說,它足夠快,同時仍然依靠數據庫來完成大部分繁重工作。迭代少於125個項目的散列似乎不是什麼大不了的事情。特別是當鍵值對只是INTS這樣的:

{ 
    0 => 0, 
    1 => 1, 
    3 => 5, 
    25 => 3, 
    99 => 3 
} 

這裏的psudo代碼:

users = User 
    .where(age: (min..max)) 
    .group(:age) 
    .count(:age) 
group = Hash.new(0) 
users.each{|age, count| 
     case 
     when age <= 10 
     group['under 10'] += count 
     when age <= 25 
     group['11-25'] += count 
     when age <= 40 
     group['26-40'] += count 
     else 
     group['41+'] += count 
     end 
} 

注:該解決方案爲用戶提供的數量在給定的範圍內。