MyModel.where(id: ids)
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'
解决方法
> expression IN (subquery)
> expression IN (value [,...])
同样,具有ANY构造的两个变体:
> expression operator ANY (subquery)
> expression operator ANY (array expression)
子查询适用于任何一种技术,但对于每种技术的第二种形式,IN需要一个值列表(如标准sql中所定义),而= ANY需要一个数组.
哪个用?
ANY是一个更加通用的新增功能,可以与任何返回布尔值的二元运算符组合使用. IN归结为任何特殊情况.事实上,它的第二种形式在内部被重写:
IN用= ANY重写
NOT IN用<>重写所有
检查EXPLAIN输出以查找任何查询以便自己查看.这证明了两件事:
> IN永远不会超过= ANY.
> =任何事情都不会快得多.
选择应该由更容易提供的内容决定:值列表或数组(可能作为数组文字 – 单个值).
如果您要传递的ID仍然来自数据库中,则直接选择它们(子查询)或使用JOIN将源表集成到查询中(如@mu commented)则更有效.
要从客户端传递一长串值并获得最佳性能,请使用数组,unexst()和join,或使用VALUES(如@PinnyM commented)将其作为表表达式提供.更多:
> Optimizing a Postgres query with a large IN
在存在NULL值的情况下,NOT IN通常是错误的选择,NOT EXISTS是正确的(也更快):
> Select rows which are not present in other table
语法= ANY
对于数组表达式,Postgres接受:
>一个array constructor(数组由Postgres一侧的值列表构成)形式:ARRAY [1,2,3]
>或“{1,3}”形式的array literal.
要避免无效的类型转换,您可以显式转换:
ARRAY[1,3]::numeric[] '{1,3}'::bigint[]
有关:
> PostgreSQL: Issue with passing array to procedure
> How to pass custom type array to Postgres function
或者你可以使用VARIADIC参数创建一个Postgres函数,该参数接受各个参数并从中形成一个数组:
> Passing multiple values in single parameter
如何从Ruby传递数组?
假设id为整数:
MyModel.where('id = ANY(ARRAY[?]::int[])',ids.map { |i| i})
但我只是涉足Ruby. @mu提供了相关答案的详细说明: