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

Eki*_*bal 11 sql postgresql activerecord ruby-on-rails-3 ruby-on-rails-4

我曾经有过如下查询:

MyModel.where(id: ids)
Run Code Online (Sandbox Code Playgroud)

哪个生成sql查询如:

SELECT "my_models".* FROM "my_models"
WHERE  "my_models"."id" IN (1, 28, 7, 8, 12)
Run Code Online (Sandbox Code Playgroud)

现在我想改为使用ANY而不是IN.我创造了这个:

MyModel.where("id = ANY(VALUES(#{ids.join '),('}))"
Run Code Online (Sandbox Code Playgroud)

现在,当我使用空数组时,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'
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 37

IN表达式有两种变体:

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

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

哪个用?

ANY是一个后来更通用的补充,它可以与任何返回布尔值的二元运算符组合.IN烧伤了一个特例ANY.实际上,它的第二种形式是在内部重写的:

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

检查EXPLAIN输出以查找任何查询以便自己查看.这证明了两件事:

  • IN永远不会快于= ANY.
  • = ANY 不会快得多.

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

如果您要传递的ID仍然来自数据库,那么直接选择它们(子查询)或将源表集成到查询中JOIN(如@mu注释)则更有效.

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

在存在NULL值的情况下,JOIN通常是错误的选择并且IN是正确的(也更快):

语法 = ANY

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

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

ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]
Run Code Online (Sandbox Code Playgroud)

有关:

或者你可以使用一个= ANY参数创建一个Postgres函数,该函数接受各个参数并从中形成一个数组:

如何从Ruby传递数组?

假设ARRAY[1,2,3]'{1,2,3}':

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

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

  • @ErwinBrandstetter考虑到OP试图通过使用值列表而不是数组来提高性能(假设[上面评论中的链接文章](https://www.datadoghq.com/blog/2013/08/100x-faster) -postgres-performance-by-changing-1-line /)仍然保持正确),答案应该使用格式`VALUES(...),(...),...`而不是`ARRAY [.. ]`.还是我错过了什么?如果文章不再正确(或从未如此),那么这个练习似乎没有任何意义...... (2认同)

归档时间:

查看次数:

13937 次

最近记录:

6 年 前