This is the case where you need to take the intersection of sets of users. In other words, you need to apply the "AND" to the sets of users, not to the where
conditions. When you chain where
conditions, you are "anding" the conditions, which is why you see the results you're seeing.
You can do this either in Ruby or in SQL, using the basic technique described in Intersection of two relations. For the sake of simplicity, I'll illustrate both here using two sets and leave the extension to more than two sets and to squeel to you.
First, let's define two sets:
set1 = User.joins(:user_skills).where('user_skills.skill_id = 10')
set2 = User.joins(:user_skills).where('user_skills.skill_id = 11 and user_skills.value >= 2')
Note: Your example text said "value higher than 2" but your code expressed "value greater than or equal to 2". I obviously used the latter interpretation above.
If you want to take the intersection in Ruby, you take the intersection of the resulting arrays, using the &
operator, as follows:
set1 & set2
In this case, you are doing two separate SQL queries and taking the intersection of the results.
If you want to take the intersection using SQL, you need to compose the SQL, which can be done using the technique described in this answer from @MikDiet to the aforementioned question:
User.connection.unprepared_statement do
User.find_by_sql "#{set1.to_sql} INTERSECT #{set2.to_sql}"
end
In this case, you are performing a single query, although that query is obviously doing "more work". You should read the original answer to understand the reason for use of unprepared_statement
.
I'll leave the extension to squeel and greater than two sets to you except to note that you can use the SQL INTERSECT
operator with more than two operands as follows:
query1 INTERSECT query2 INTERSECT query3 ...