5

讓我們說,我有一組ID(從客戶端接收的):使用與Rails的準備語句的語法其中

myArray = [1,5,19,27]

而且我想返回所有項目將(二次)id在該列表中。

在SQL這將是:

SELECT * FROM Items WHERE id IN (1,5,19,27)

我知道我能做到:

Item.where(id: [1,5,9,27])

但是不再在那裏查詢,這將是上漲到使用準備語句語法Item.where('myAttrib = ? AND myOtherAttrib <> ? AND myThirdAttrib = ?', myVal[0], myVa[1], myVal[2])

考慮到這一點,我想是這樣的:

Item.where('id IN ?', myArray)

然而,這會產生一個語法錯誤:

ActiveRecord::StatementInvalid: PG::Error: ERROR: syntax error at or near "1" LINE 1: SELECT "items".* FROM "items" WHERE (id in 1,2,3,4)

我如何解決此問題?使用IN表達式的預準備語句語法的正確方法是什麼?

回答

2

您需要查詢更改爲以下:

Item.where('id = ?', myArray) 

的ActiveRecord然後將其轉換爲IN子句如果myarray的是,事實上,一個數組。

6

我最終使用:

Item.where('id IN (?)', myArray)

0

使用原始SQL的問題是,你失去了列名的自動命名空間提供了通過Rails和AREL免費多數民衆贊成。

使用原始的sql可能會在組合和合並查詢或作用域或進行連接時引發問題。

無需使用原始SQL使用IN

Item.where(:id => myArray) # SELECT * FROM items WHERE id IN (...) 

myArray可以是值的陣列或Items陣列,或一個單一的值。

Rails很聰明,可以根據你的意思更改SQL。事實上,如果數組包含nil,則SQL將爲SELECT * FROM items WHERE (id IS NULL or id IN (...))。這明顯優於使用靜態的原始SQL,並且只能處理單個用例。

如果Rails不提供您所需的東西,您可以回退到AREL。例如:

class Item 
    scope :with_category, ->(categories) { 
    where(arel_table[:category].in(categories)) 
    } 

    scope :filter, ->(a, b, c) { 
    not_b = arel_table[:myOtherAttrib].not_eq(b) 
    where(:myAttrib => a, :myThirdAttrib => c).where(not_b) 
    } 
end 

Item.with_category(['small', 'large']).filter(*myVal)