简体   繁体   中英

Sql query equivalent in Rails' Active Record

Rails noob here...I'm trying to find the best option in my rails project. I have a sql query like this:

select sum(count) from (select count(user_id) as 'count' from accounts group by user_id having count(user_id) > 2) as A

All its trying to do is get the sum of count of users that have more than 2 accounts. While this sql query works fine by itself, I'm trying to find a way to translate this to Active Record. Users and Accounts are rails models in my project.

I'm assuming User has a has_many relationship with Accounts? In that case, you can do something like

 User.find(id).accounts.count  

and each time a user with a particular id has >= 2 accounts, you can add 1 to the total count.

Or you could do something like

count = 0
@users = User.all 
@users.each do |user|
   if user.accounts.count >= 2
     count += 1
   end
end

Hopefully this is something you were looking for.

timmy's solution should work, but will cause N+1 queries . You can use .includes to eager load what you need in order to minimize queries to the database (I too assume you have set up your has_many and belongs_to association between users and accounts). I believe this would be the optimized implementation:

users = User.includes(:accounts)
count = 0

users.each do |user|
  count += 1 if user.accounts.count > 2
end

I believe you could even refactor this further by chaining on a .where, but I am not quite sure how. check the documentation page I linked to at the top.

Hope that helps.

As per the sql query provided by you, Account model (accounts table) has a column named user_id which you are using for grouping. First step is to group by user_id and find user wise account counts. This will create a hash looking like { u1: n_acc1, u2: n_acc2 } . The select statement selects all (key: value) user_id: n_accounts pairs where n_accounts > 2 . Then you just need to map (value) n_accounts into an array and apply sum on it.

Account.group(:user_id).count
       .select{ |user_id, n_accounts| n_accounts > 2 }
       .map{ |user_id, n_accounts| n_accounts }
       .sum

No need to use association and/or eager loading . Should be faster than the other solutions. Also, issues a single db query to find grouped count, rest all calculations would be on ruby side.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM