ActiveRecordでBETWEEN的な範囲指定検索をしたいケースがあり、挙動を調べたので整理してみました。
( ※Rails 5.2.0, MySqlで確認しています。)
以下のようにRangeで表現することができます。
User.where(id: from..to)
通常の範囲指定
検索条件に1..10
を指定すると、BETWEEN句に変換してくれます。
User.where(id: 1..10)
SELECT `users`.* FROM `users` WHERE `users`.`id` BETWEEN 1 AND 10 LIMIT 11
from以上
toにFloat::INFINITY
を指定すると、BETWEEN句ではなく空気を読んでid >= 1
に変換してくれます。すごい!
User.where(id: 1..Float::INFINITY)
SELECT `users`.* FROM `users` WHERE `users`.`id` >= 1 LIMIT 11
to以下
逆にfromFloat::MIN
を指定すると、idの最小値=0に置き換え(DBの型から判別してる?)、BETWEEN句に変換してくれます。
User.where(id: Float::MIN..10)
SELECT `users`.* FROM `users` WHERE `users`.`id` BETWEEN 0 AND 10 LIMIT 11
from/toが同値
from/toに同値を指定すると、BETWEEN 1 AND 1
となりました。
id = 1
を期待していたのですが、1件なら性能も大差ないでしょうし問題なさそうです。
ruby
User.where(id: 1..1)
sql
SELECT `users`.* FROM `users` WHERE `users`.`id` BETWEEN 1 AND 1 LIMIT 11
おすすめの範囲指定
上記の挙動をふまえ、以下のようなコードに落ち着きました。
from = query.id_from.blank? ? Float::MIN : query.id_from
to = query.id_to.blank? ? Float::INFINITY : query.id_to
User.where(id: from..to)
ActiveRecordは便利な機能がたくさんあって面白いですね!しっかり勉強していこうと思います。
もっとスマートな書き方あるよ!という方いましたらぜひ教えてください!