简体   繁体   中英

Using WHERE IN with Rails prepared statement syntax

Let us say I have an array (received from the client side) of ids:

myArray = [1,5,19,27]

And I would like to return ALL items for which the (secondary) id is in that list.

In SQL this would be:

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

I am aware that I could do:

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

however the longer where query that this would be tacked onto uses the prepared statement syntax Item.where('myAttrib = ? AND myOtherAttrib <> ? AND myThirdAttrib = ?', myVal[0], myVa[1], myVal[2])

with that in mind, what I would like is the following:

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

However, that produces a syntax error:

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

How can I work around this? What is the right way to use where with the prepared statement syntax for IN expressions.

我最终使用:

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

You need to change your query to the following:

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

ActiveRecord will then convert this to an IN clause if myArray is, in fact, an array.

The issue with using raw sql is that the you loose the automatic namespacing of column names thats provided for free by Rails and AREL.

Using raw sql can start causing issues when combining and merging queries or scopes, or when doing joins.

No need to use raw sql to use IN :

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

myArray can either be an array of values or an array of Items , or a single value.

Rails is smart enough to change the SQL to what you mean. Infact, if the array contains nil , the SQL will be SELECT * FROM items WHERE (id IS NULL or id IN (...)) . This is clearly superior to using raw SQL which is static and only capable of dealing with a single use case.

If Rails doesn;t provide you with what you need, you can fall back to AREL. For example:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM