Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Is there a cleaner way to do the following?

friend_ids = [1,2,3,4,5]
friendIDsQuery = ""
friend_ids.each_with_index do |friend_id, index|
  friendIDsQuery += "SELECT id FROM test WHERE user_id = #{friend_id}"

  if index != friend_ids.size - 1
    friendIDsQuery += " INTERSECT "
  end
end

Basically I'm passing in an array of IDs, and building a custom INTERSECT query.

share|improve this question
2  
you wrote Array#join by hand... – tokland Oct 11 '12 at 10:42

2 Answers

This would be the more idiomatic Rails form, without so much SQL.

friend_ids.
  map {|fid| Test.select(:id).where(:user_id => fid) }.
  reduce {|a,e| a = a & e }

If you really need the sql, then append:

.to_sql

share|improve this answer
You're missing the intersection-part. As far as I can tell, OP isn't trying to find ids where user_id IN (...), but the intersection of multiple selections. – Flambino Oct 17 '12 at 17:57
@Flambino you're right. Here is the correct for with intersections. I do concede that leaving the intersects within the database may be more performant than to do N queries and then operate upon them. – NewAlexandria Oct 18 '12 at 2:35
1  
+1. I'd say your solution has the distinct advantage of not generating a query string "by hand". In my answer I'm assuming that the IDs are safe - otherwise, well, hello injection attacks (should probably note that in my answer). Meanwhile, you're assuming that it's Rails. Very probable, but OP doesn't say. As for performance, your guess is as good as mine - OP doesn't say mention anything about the number of queries. – Flambino Oct 18 '12 at 16:24
1  
the OP didn't specify whether ActiveRecord or Rails was being used. Anyway, refactor of the reduce: reduce([], :&). – tokland Oct 25 '12 at 13:50
@tokland though arcane, that's hot – NewAlexandria Oct 25 '12 at 13:53
query = friend_ids.map {|id| "SELECT id FROM test WHERE user_id=#{id}"}.join " INTERSECT "

Bam.

Edit: Ok, well, not just bam. First of all, if you're using Rails, go with something like NewAlexandria's answer, because it doesn't involve raw string interpolation (which quickly leads to SQL injection vulnerabilities). To make the above a little more safe (and assuming the IDs are integers), you should probably do

query = friend_ids.map { |id|
  "SELECT id FROM test WHERE user_id = #{id.to_i}"
}.join " INTERSECT "
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.