如何在Rails的WHERE子句中使用ANY而不是IN?

我曾经有一个像这样的查询:

MyModel.where(id: ids) 

其中生成sql查询如下所示:

 SELECT "my_models".* FROM "my_models" WHERE "my_models"."id" IN (1, 28, 7, 8, 12) 

现在我想改变这个使用ANY而不是IN 。 我创build了这个:

 MyModel.where("id = ANY(VALUES(#{ids.join '),('}))" 

现在,当我使用空数组ids = []我得到以下错误:

 MyModel Load (53.0ms) SELECT "my_models".* FROM "my_models" WHERE (id = ANY(VALUES())) ActiveRecord::JDBCError: org.postgresql.util.PSQLException: ERROR: syntax error at or near ")" ActiveRecord::StatementInvalid: ActiveRecord::JDBCError: org.postgresql.util.PSQLException: ERROR: syntax error at or near ")" Position: 75: SELECT "social_messages".* FROM "social_messages" WHERE (id = ANY(VALUES())) from arjdbc/jdbc/RubyJdbcConnection.java:838:in `execute_query' 

INexpression式有两种变体:

  • expression IN (subquery)
  • expression IN (value [, ...])

同样, ANY构造有两个变体:

  • expression operator ANY (subquery)
  • expression operator ANY (array expression)

一个子查询适用于任何一种技术,但是对于每种技术的第二种forms, IN需要一个值列表 (在标准SQL中定义),而= ANY需要一个数组

使用哪个?

ANY是一个更新,更通用的补充,它可以与任何返回布尔值的二元运算符结合使用。 IN烧伤了ANY一个特殊情况。 事实上,它的第二种forms是内部改写的:

IN被改写为= ANY
NOT IN<> ALL重写

检查EXPLAIN输出以查看任何查询。 这certificate了两件事:

  • IN永远不会比= ANY快。
  • = ANY不会快得多。

select应该由容易提供内容决定:值列表或数组(可能是数组字面值 – 单个值)。

如果要传递的ID 来自数据库 ,则直接select它们(子查询)或将源表与JOIN (如@mu注释 )集成到查询中效率更高 。

要从客户端传递一长串值并获得最佳性能 ,请使用数组unnest()和join,或者使用VALUES (如@PinnyM注释 )将其作为表expression式提供。 更多:

  • 用一个大的IN优化一个Postgres查询

在存在NULL值的情况下, NOT IN通常是错误的select, NOT EXISTS将是正确的(也是更快的):

  • select其他表中不存在的行

语法for = ANY

对于Postgres接受的数组expression式:

  • 一个数组构造函数 (数组是从Postgres一侧的值列表构造的): ARRAY[1,2,3]
  • 或forms为'{1,2,3}'数组字面值

为了避免无效的types转换,你可以明确地强制转换:

 ARRAY[1,2,3]::numeric[] '{1,2,3}'::bigint[] 

有关:

  • PostgreSQL:将数组传递给过程的问题
  • 如何将自定义types数组传递给Postgres函数

或者你可以创build一个采用VARIADIC参数的Postgres函数,该参数需要单独的参数并从中形成一个数组:

  • 在单个参数中传递多个值

如何从Ruby传递数组?

假设idinteger

 MyModel.where('id = ANY(ARRAY[?]::int[])', ids.map { |i| i}) 

但是我只是在讨论Ruby。 @mu在这个相关的答案中提供了详细的说明:

  • 发送值的数组到Ruby中的SQL查询?