joins vs include?

I know this is probably a noob question, but I needed a little clarification. I did the following in the console of my app:

User.find(:all, :conditions => "orders.id > 1", :joins => :orders).size

=> 1254

User.find(:all, :conditions => "orders.id > 1", :include => :orders).size

=> 934

A user has many orders. Why am I getting different results? When using fields in a has_many relationship should I ALWAYS use the :include option. I did the reverse too:

Order.find(:all, :conditions => "users.id < 100", :joins => :user).size

=> 172

Order.find(:all, :conditions => "users.id < 100", :include => :user).size

=> 172

I'm getting the same result. What is the general rule of thumb on when to use joins or includes?

Thanks for your help!

How did you populate your tables?

I am sure it is an issue about LEFT JOIN, i.e: all records from left table will appear in the result even if they don't have matches on the right table.

As an order always has a user, :joins and :include return the same number of rows. Whereas, a user doesn't necessarily have an order, but he will still appear in the result with a left join.

I know this is probably a noob question, but I needed a little clarification. I did the following in the console of my app:

User.find(:all, :conditions => "orders.id > 1", :joins
=> :orders).size

=> 1254

User.find(:all, :conditions => "orders.id > 1", :include
=> :orders).size

=> 934

A user has many orders. Why am I getting different results? When using fields in a has_many relationship should I ALWAYS use the :include option. I did the reverse too:

Order.find(:all, :conditions => "users.id < 100", :joins
=> :user).size

=> 172

Order.find(:all, :conditions => "users.id < 100", :include
=> :user).size

=> 172

I'm getting the same result. What is the general rule of thumb on when to use joins or includes?

See http://www.spacevatican.org/2008/6/22/the-difference-between-include-and-joins .

The difference between your two cases is that a user can have many
orders: for each user you'll get a result for each object, whereas an
order can only ever have one user.

Fred

Thanks for your help. I am still somewhat confused though.

So is the general rule of thumb to use joins on belongs to relationships and include on has_many. It looks as if joins returns flawed results is used on a has_many relationship. Is this correct?

I would prefer to avoid include because it is so much slower, but joins doesnt seem to return the correct records.

Thanks.

Thanks for your help. I am still somewhat confused though.

So is the general rule of thumb to use joins on belongs to relationships and include on has_many. It looks as if joins returns flawed results is used on a has_many relationship. Is this correct?

No. Use :joins when you want a join. Use include when you want to avoid the n+1 problem (ie you want rails to load and populate the associations).

Fred

Frederick Cheung wrote:

Thanks for your help. I am still somewhat confused though.

So is the general rule of thumb to use joins on belongs to relationships and include on has_many. It looks as if joins returns flawed results is used on a has_many relationship. Is this correct?

No. Use :joins when you want a join. Use include when you want to avoid the n+1 problem (ie you want rails to load and populate the associations).

Fred

Thanks for your help. I agree, I would prefer to use joins, but they do not return the proper results. It seems that joins return duplicate results:

User.find(:all, :conditions => "orders.id > 1", :joins => :orders).size

=> 1254

User.find(:all, :conditions => "orders.id > 1", :include => :orders).size

=> 934

In the above example the first query is returning duplicate results. I am getting users with the same ID. I'm confused why it would return duplicate results. Any idea why this is? Seeing as this is a problem it seems that :include is my only option.

Thanks.

It also seems that the following works just fine:

User.find(:all, :conditions => "orders.id > 1", :joins => :orders, :group => "users.id").size => 934

I apologize for my ignorance in this situation, but is the above search "improper"? Is there a better way to do this?

Thanks.

If your users table had exactly one user, and that user had 2 orders, then

select * from users inner join orders on orders.user_id = users.id

would return the result set (i've made up some column names)

users.id | users.name | orders.id | orders.name| 1 | bob | 1 | a tv 1 | bob | 2 | a dvd

This is just how joins are supposed to work. I'm still not sure what you're trying to achieve in the first place (but grouping or using select distinct may be options)

:include is different (and doesn't even use joins half the time). It's doing a lot of work behind the scenes wiring up associations.

Fred