2016-05-12 33 views
1

我有一個查詢需要從滿足兩列需求的表中獲取。所以如果我有users列的表,agescore活動記錄 - 其中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) 

最後,您的查詢就會

User.where(query_string) 

您可以糾正如何構建查詢字符串,因爲ages_and_scores是不同的格式,以我的例子的邏輯。

改進

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:

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

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

在PG數據庫,你可以直接的毗連使用:

(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. 單獨從陣列
  2. 第一值對獲取AREL表,這樣就可以構建查詢
  3. 使用來自Ruby的Enumerableinject方法模塊遍歷整個數組的其餘部分,並添加所有or條件......但是從第一個where查詢中的前兩個值開始。

最後,您將有一個Arel查詢,它將返回符合條件的所有用戶......並且它應該可以在Rails(Arel)支持的任何數據庫中工作。