以前は次のようなクエリがありました。
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
式には2つのバリエーションがあります。
同様に、ANY
構造を持つ2つのバリアント:
サブクエリはどちらの手法でも機能しますが、それぞれのsecond形式の場合、IN
は値のリスト(標準SQLで定義)を期待しますが、_= ANY
_はarrayを期待します。
ANY
は後の、より用途の広い加算であり、ブール値を返す任意の二項演算子と組み合わせることができます。 IN
はANY
の特別な場合に燃え尽きます。実際、その2番目の形式は内部で書き直されています。
IN
は_= ANY
_で書き直されます
_NOT IN
_は_<> ALL
_で書き直されます
クエリのEXPLAIN
出力を確認して、自分で確認してください。これは2つのことを証明します:
IN
は_= ANY
_より速くなることはありません。= ANY
_は大幅に高速化されることはありません。選択は提供しやすいもの:値のリストまたは配列(おそらく配列リテラルとして-単一の値)によって決定する必要があります。
渡すIDが来た場合DB内からとにかく、IDを直接選択するか(サブクエリ)、ソーステーブルをJOIN
でクエリに統合する方がはるかに効率的です。 ( @ muコメント のように)。
クライアントから長いリストの値を渡し、最高の値を取得するにはパフォーマンス =、配列unnest()
を使用して結合するか、VALUES
を使用してテーブル式として提供します( @ PinnyMコメント など)。ただし、JOIN
は、提供された配列/セットで可能なduplicatesを保持しますが、IN
または_= ANY
_は保持しないことに注意してください。もっと:
NULL値が存在する場合、_NOT IN
_はしばしば間違った選択であり、_NOT EXISTS
_は正しい(そしてより高速でもある)でしょう:
= ANY
_の構文配列式の場合、Postgresは以下を受け入れます。
ARRAY[1,2,3]
_'{1,2,3}'
_の形式。無効な型キャストを回避するために、明示的にキャストできます。
_ARRAY[1,2,3]::numeric[]
'{1,2,3}'::bigint[]
_
関連:
または、 could VARIADIC
パラメータを使用してPostgres関数を作成します。この関数は、個々の引数を受け取り、それらから配列を形成します。
id
をinteger
と仮定します。
_MyModel.where('id = ANY(ARRAY[?]::int[])', ids.map { |i| i})
_
しかし、私はRubyに手を出しているだけです。 @muは、この関連する回答で詳細な手順を提供します。