2
\$\begingroup\$

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.

\$\endgroup\$
  • 2
    \$\begingroup\$ you wrote Array#join by hand... \$\endgroup\$ – tokland Oct 11 '12 at 10:42
4
\$\begingroup\$
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 "
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

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

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – Flambino Oct 17 '12 at 17:57
  • \$\begingroup\$ @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. \$\endgroup\$ – New Alexandria Oct 18 '12 at 2:35
  • 1
    \$\begingroup\$ +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. \$\endgroup\$ – Flambino Oct 18 '12 at 16:24
  • 1
    \$\begingroup\$ the OP didn't specify whether ActiveRecord or Rails was being used. Anyway, refactor of the reduce: reduce([], :&). \$\endgroup\$ – tokland Oct 25 '12 at 13:50
  • \$\begingroup\$ @tokland though arcane, that's hot \$\endgroup\$ – New Alexandria Oct 25 '12 at 13:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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