如何在 WHERE 子句中使用 ANY 而不是 IN?
How to use ANY instead of IN in a WHERE clause?
我曾经有一个像 Rails 中的查询:
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'
IN
表达式有两种变体:
类似地,具有 ANY
构造的两个变体:
子查询适用于任何一种技术,但对于每种技术的 second 形式,IN
需要一个 值列表 (如标准 SQL 中所定义)而 = ANY
需要一个 数组 .
使用哪个?
ANY
是后来更通用的加法,它可以与任何返回布尔值的二元运算符结合使用。 IN
归结为 ANY
的特例。其实它的第二种形式是内部改写的:
IN
改写为 = ANY
NOT IN
改写为 <> ALL
检查 EXPLAIN
输出以了解任何查询。这证明了两件事:
IN
永远不会比 = ANY
. 快
= ANY
不会明显变快。
应根据哪个更容易提供来决定:值列表或数组(可能是数组文字 - 单个值)。
如果您要传递的 ID 来自数据库 无论如何,直接 select 它们(子查询)或集成源会更有效table 进入带有 JOIN
的查询(例如 )。
从您的客户端传递一个 长列表 值并获得最佳 性能,使用数组,unnest()
并连接,或使用 VALUES
(如 )将其作为 table 表达式提供。但请注意,JOIN
会在提供的数组/集合中保留可能的 重复项 ,而 IN
或 = ANY
则不会。更多:
在存在 NULL 值的情况下,NOT IN
通常是错误的选择,而 NOT EXISTS
是正确的(而且速度也更快):
- Select rows which are not present in other table
= ANY
的语法
对于 Postgres 接受的数组表达式:
- 一个 array constructor(数组由 Postgres 端的值列表构成),形式为:
ARRAY[1,2,3]
- 或
'{1,2,3}'
. 形式的 array literal
为避免无效类型转换,您可以显式转换:
ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]
相关:
- How to pass custom type array to Postgres function
或者您 可以 创建一个带有 VARIADIC
参数的 Postgres 函数,它接受单独的参数并从中形成一个数组:
如何从Ruby传递数组?
假设 id
为 integer
:
MyModel.where('id = ANY(ARRAY[?]::int[])', ids.map { |i| i})
但我只是涉足Ruby。 @mu 在此相关答案中提供了详细说明:
- Sending array of values to a sql query in ruby?
我曾经有一个像 Rails 中的查询:
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'
IN
表达式有两种变体:
类似地,具有 ANY
构造的两个变体:
子查询适用于任何一种技术,但对于每种技术的 second 形式,IN
需要一个 值列表 (如标准 SQL 中所定义)而 = ANY
需要一个 数组 .
使用哪个?
ANY
是后来更通用的加法,它可以与任何返回布尔值的二元运算符结合使用。 IN
归结为 ANY
的特例。其实它的第二种形式是内部改写的:
IN
改写为 = ANY
NOT IN
改写为 <> ALL
检查 EXPLAIN
输出以了解任何查询。这证明了两件事:
IN
永远不会比= ANY
. 快
= ANY
不会明显变快。
应根据哪个更容易提供来决定:值列表或数组(可能是数组文字 - 单个值)。
如果您要传递的 ID 来自数据库 无论如何,直接 select 它们(子查询)或集成源会更有效table 进入带有 JOIN
的查询(例如
从您的客户端传递一个 长列表 值并获得最佳 性能,使用数组,unnest()
并连接,或使用 VALUES
(如 JOIN
会在提供的数组/集合中保留可能的 重复项 ,而 IN
或 = ANY
则不会。更多:
在存在 NULL 值的情况下,NOT IN
通常是错误的选择,而 NOT EXISTS
是正确的(而且速度也更快):
- Select rows which are not present in other table
= ANY
的语法
对于 Postgres 接受的数组表达式:
- 一个 array constructor(数组由 Postgres 端的值列表构成),形式为:
ARRAY[1,2,3]
- 或
'{1,2,3}'
. 形式的 array literal
为避免无效类型转换,您可以显式转换:
ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]
相关:
- How to pass custom type array to Postgres function
或者您 可以 创建一个带有 VARIADIC
参数的 Postgres 函数,它接受单独的参数并从中形成一个数组:
如何从Ruby传递数组?
假设 id
为 integer
:
MyModel.where('id = ANY(ARRAY[?]::int[])', ids.map { |i| i})
但我只是涉足Ruby。 @mu 在此相关答案中提供了详细说明:
- Sending array of values to a sql query in ruby?