2011-02-17 25 views
23

每節2.2上的Active Record查詢接口here導軌導向:如何指定多個值,其中在Rails3中AR查詢界面

這似乎表明,我可以通過一個字符串指定條件(S),然後是在構建arel時某個點應該替換的值的數組。所以我得到了一個聲明來生成我的條件字符串,它可以是不同數量的屬性,通過它們之間的AND或OR連接在一起,並且我將一個數組作爲第二個參數傳遞給where方法,我得到:

的ActiveRecord :: PreparedStatementInvalid:錯號碼綁定變量(1 5)

這使我相信,我錯誤地這樣做。然而,我沒有找到任何關於如何正確地做到這一點。換句話說,我需要將一個字符串傳遞給where方法,比如「table.attribute =?AND table.attribute1 =?OR table.attribute1 =?」將這些條件的數量未知數聯繫在一起,然後傳遞一些東西,我認爲這將是一個數組作爲第二個參數,用於替換第一個參數條件字符串中的值。這是正確的方法,還是我在某個地方錯過了一些其他巨大的概念,而我在這一切都是錯誤的?我認爲,這應該是可能的,但只是生成一個原始的sql字符串。

+2

如果你發佈你遇到問題的代碼,這會是有益的豐富。 – mharper 2011-02-17 22:22:18

+0

好吧,Dan在下面發佈的代碼幾乎是我想要做的,除了我不知道會有多少條件,因此也不知道有多少個替換。所以,我認爲我可以傳遞一個包含要替換的值的數組作爲第二個參數。 – wkhatch 2011-02-18 06:49:14

+0

「不同數量的屬性通過它們之間的AND或OR連接在一起」據我瞭解,該條件可以匹配任何給定的屬性,也可以匹配所有屬性但不匹配二者。像`attribute =? OR attribute2 =? OR attribute3 =?`或`attribute =? AND attribute2 =? AND attribute3 =?`。 – 2012-09-27 08:02:07

回答

19

聽起來你正在做這樣的事情:

Model.where("attribute = ? OR attribute2 = ?", [value, value]) 

而你需要做的是:

# notice the lack of an array as the last argument 
Model.where("attribute = ? OR attribute2 = ?", value, value) 

看一看http://guides.rubyonrails.org/active_record_querying.html#array-conditions關於如何工作的更多細節。

+0

是的,問題是,我不知道有多少這些條件會存在,直到運行時,所以我動態地構造了第一個字符串參數。我想我可以在字符串中插入我需要匹配的值,但那肯定不太安全。似乎有一個更簡單的方法來傳遞多個值參數,但我猜不是。感謝您的回覆 – wkhatch 2011-02-18 06:44:38

+13

我還沒有嘗試過,但您可以嘗試在參數值數組上使用splat運算符:`Model.where(「attributes =?」,* array_of_values)` – 2011-02-20 22:14:59

+3

最後一條評論中的語法doesn不幸的是,工作。 – mahemoff 2012-05-23 14:39:13

4

如果你想鏈接一個開放式的條件列表(屬性名稱和值),我會建議使用一個arel表。

這是一個有點很難給具體,因爲你的問題是如此模糊,所以我就解釋一下如何爲Post模型的一個簡單的例子和​​幾個屬性做到這一點,說titlesummaryuser_id(即用戶has_many帖子)。

首先,獲得AREL表型號:

table = Post.arel_table 

然後,開始建立您的謂詞(你最終會用它來創建一個SQL查詢):

relation = table[:title].eq("Foo") 
relation = relation.or(table[:summary].eq("A post about foo")) 
relation = relation.and(table[:user_id].eq(5)) 

這裏,table[:title]table[:summary]table[:user_id]posts表中列的表示。當您調用table[:title].eq("Foo")時,您正在創建謂詞,大致等同於查找條件(獲取標題列等於「Foo」的所有行)。這些謂詞可以與andor鏈接在一起。

當你的總謂詞是準備好了,你可以得到的結果是:

Post.where(relation) 

這將生成SQL:

SELECT "posts".* FROM "posts" 
WHERE (("posts"."title" = "Foo" OR "posts"."summary" = "A post about foo") 
AND "posts"."user_id" = 5) 

這將讓你有任何標題的所有帖子「 Foo「或摘要」關於foo的帖子「,,它們屬於具有ID 5的用戶。

請注意,arel謂詞可以b無盡地鏈接在一起創造更多和更復雜的查詢。這意味着如果你有(比如說)屬性/值對的哈希值以及某種方式知道每個上面是否使用ANDOR,則可以逐一循環並構建條件:

relation = table[:title].eq("Foo") 
hash.each do |attr, value| 
    relation = relation.and(table[attr].eq(value)) 
    # or relation = relation.or(table[attr].eq(value)) for an OR predicate 
end 
Post.where(relation) 
從方便鏈接條件

除此之外,AREL表的另一個優點是,他們是獨立的數據庫,所以你不必擔心你的MySQL查詢是否將在PostgreSQL的工作,等

這裏有一個Railscast更多關於arel:http://railscasts.com/episodes/215-advanced-queries-in-rails-3?view=asciicast

希望有所幫助。

2

您可以使用散列而不是字符串。建立一個散列,其中包含許多條件和相應的值,並將其放入where方法的第一個參數中。

18

取而代之的是相同的參數多次傳遞給where()這樣

User.where(
    "first_name like ? or last_name like ? or city like ?", 
    "%#{search}%", "%#{search}%", "%#{search}%" 
) 

,你可以很容易地提供一個哈希

User.where(
    "first_name like :search or last_name like :search or city like :search", 
    {search: "%#{search}%"} 
) 

,使你的查詢更可讀長參數列表。

31

這其實很簡單:

Model.where(attribute: [value1,value2]) 
11

聽起來你正在做這樣的事情:

Model.where("attribute = ? OR attribute2 = ?", [value, value]) 

而你需要做的是:

#notice the lack of an array as the last argument 
Model.where("attribute = ? OR attribute2 = ?", value, value) Have a 

看看 http://guides.rubyonrails.org/active_record_querying.html#array-conditions 有關這是如何工作的更多細節。

真的很接近。您可以使用* my_list將數組轉換爲參數列表。

Model.where("id = ? OR id = ?", *["1", "2"]) 

OR

params = ["1", "2"] 
Model.where("id = ? OR id = ?", *params) 

應工作

1

WRONG 這是我用了一段的理由這樣做。

keys = params[:search].split(',').map!(&:downcase) 
# keys are now ['brooklyn', 'queens'] 

query = 'lower(city) LIKE ?' 

if keys.size > 1 
    # I need something like this depending on number of keys 
    # 'lower(city) LIKE ? OR lower(city) LIKE ? OR lower(city) LIKE ?' 
query_array = [] 
keys.size.times { query_array << query } 
#['lower(city) LIKE ?','lower(city) LIKE ?'] 
query = query_array.join(' OR ') 
# which gives me 'lower(city) LIKE ? OR lower(city) LIKE ?' 
end 
# now I can query my model 
# if keys size is one then keys are just 'brooklyn', 
# in this case it is 'brooklyn', 'queens' 
# @posts = Post.where('lower(city) LIKE ? OR lower(city) LIKE ?','brooklyn', 'queens') 
@posts = Post.where(query, *keys) 

現在,但是 - 是的 - 它非常簡單。作爲nfriend21提到

Model.where(attribute: [value1,value2])

做同樣的事情

相關問題