2016-05-12 6 views
1

2つの列の要件を厳密に満たすテーブルからフェッチする必要があるクエリがあります。だから私はとscore とテーブルusersを持っている場合。アクティブレコード - 複数の列を持つIN

SELECT * FROM users where (age, score) IN ((5,6), (9,12), (22,44)..) 

私のWebアプリケーションでは、このペアをajaxリクエストから取得していますが、その数はかなり大きくなる可能性があります。このためのActive Recordクエリを作成するにはどうすればよいですか。私はPostgresデータベース理想的

答えて

3

に取り組んでいます

、我々は、入力に基づいてクエリ文字列を構築します。例えば

ages_and_scores = [ [5, 6], [9, 12], [22, 44] ] 
query_string = ages_and_scores.map do |pair| 
    "(age = #{pair[0]} AND score = #{pair[1]})" 
end.join(" OR ") 
# => (age = 5 AND score = 6) OR (age = 9 AND score = 12) OR (age = 22 AND score = 44) 

最後に、あなたのクエリがages_and_scoresは私の例とは異なるフォーマットであるので、あなたは、クエリ文字列を構築する方法のロジックを補正してもよい

User.where(query_string) 

になります。

改善

ages_and_scores = [ [5, 6], [9, 12], [22, 44] ] 
query_params = [] 

query_template = ages_and_scores.map{ |_| "(age = ? AND score = ?)" }.join(" OR ") 
# => (age = ? AND score = ?) OR (age = ? AND score = ?) OR (age = ? AND score = ?) 

User.where(query_template, *ages_and_scores.flatten) 
+0

私はSQLインジェクションにこのように脆弱ですか? – coderVishal

+0

@coderVishal私の改善を確認してください –

+0

@coderVishalこれは役に立ちますか? –

1

ねえ、あなたは、MySQLでこの方法を試すことができます。

あなたが直接、連結方式を使用することができPGデータベースで
ages_and_scores = [ [5, 6], [9, 12], [22, 44] ] 

User.where("CONCAT(age,',', score) in (?)",ages_and_scores.map{|b| "#{b[0]},#{b[1]}"}) 

(age || ' ,' || score) 
1

を別の解決策は次のようになりArelを使用すると、D Bにとらわれない。

ages_and_scores = [ [5, 6], [9, 12], [22, 44] ] 
first_age, first_score = ages_and_scores.shift 
t = User.arel_table 
users = ages_and_scores.inject(User.where(t[:age].eq(first_age)).where(t[:score].eq(first_score))) { |query, age_score| query.or(User.where(t[:age].eq(age_score[0])).where(t[:score].eq(age_score[1]))) } 

基本的にこれがどのように機能するか:

  1. あなたはRubyのEnumerableからinjectメソッドを使用して、クエリ
  2. を構築することができるように配列
  3. から最初の値のペアがARELテーブルを取得する区切りモジュールは、or条件のすべてを追加する配列の残りの部分を反復処理しますが、最初のwhereクエリの最初の2つの値から始まります。

最後に、あなたはあなたの条件に一致するすべてのユーザーを返すArelクエリを持っています...そして、それはRailsの(AREL)でサポートされている任意のDB間で動作するはずです。

関連する問題