我曾经有过如下查询:
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'
答案 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接受:
= ANY
ARRAY[1,2,3]
形式的array literal。 为了避免无效的类型转换,您可以显式转换:
'{1,2,3}'
相关:
或者你可以创建一个带有ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]
参数的Postgres函数,该参数接受各个参数并从中形成一个数组:
假设VARIADIC
为id
:
integer
但我只是涉足Ruby。 @mu提供了相关答案中的详细说明: