7

假设我有一个 id 数组(从客户端接收):

myArray = [1,5,19,27]

我想返回(辅助)ID 在该列表中的所有项目。

在 SQL 中,这将是:

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

我知道我可以这样做:

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

但是,在 where 查询中添加的时间越长,使用准备好的语句语法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)

我该如何解决这个问题?将 where 与表达式的准备好的语句语法一起使用的正确方法是什么IN

4

3 回答 3

14

我最终使用:

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

于 2013-09-30T17:57:56.827 回答
3

您需要将查询更改为以下内容:

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

如果 myArray 实际上是一个数组,那么 ActiveRecord 会将其转换为 IN 子句。

于 2013-09-29T08:38:19.987 回答
1

使用原始 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)
于 2015-11-06T01:48:18.800 回答