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

时间:2015-07-02 17:59:38

标签: sql ruby-on-rails-3 postgresql ruby-on-rails-4 activerecord

我曾经有过如下查询:

MyModel.where(id: ids)

生成sql查询,如:

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

现在我想将其更改为使用ANY而不是IN。我创造了这个:

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'

1 个答案:

答案 0 :(得分:32)

IN表达式有两种变体:

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

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

使用哪种?

ANY是一个更加通用的新增功能,可以与任何返回布尔值的二元运算符组合使用。 IN归结为ANY的特例。实际上,它的第二种形式是在内部重写的:

IN= ANY改写 用NOT IN

重写<> ALL

检查EXPLAIN输出是否有任何查询可供您查看。这证明了两件事:

  • IN永远不会比= ANY快。
  • = ANY的速度不会太快。

选择应该由更容易提供决定:值列表或数组(可能是数组文字 - 单个值)。

如果您要传递的ID无论如何都来自数据库中的,直接选择它们(子查询)或将源表集成到{{1 (如@mu commented)。

要从客户端传递 长列表 值并获得最佳 性能 ,请使用数组,JOIN并加入,或使用unnest()(如@PinnyM commented)将其作为表格表达式提供。更多:

如果存在NULL值,VALUES通常是错误的选择,NOT IN也是正确的(也会更快):

NOT EXISTS

的语法

对于数组表达式,Postgres接受:

为了避免无效的类型转换,您可以显式转换:

'{1,2,3}'

相关:

或者你可以创建一个带有ARRAY[1,2,3]::numeric[] '{1,2,3}'::bigint[] 参数的Postgres函数,该参数接受各个参数并从中形成一个数组:

如何从Ruby传递数组?

假设VARIADICid

integer

但我只是涉足Ruby。 @mu提供了相关答案中的详细说明: