200を超えるIDを持つすべてのユーザーを検索しようとしていますが、特定の構文に問題があります。
User.where(:id > 200)
そして
User.where("? > 200", :id)
両方とも失敗しました。
助言がありますか?
200を超えるIDを持つすべてのユーザーを検索しようとしていますが、特定の構文に問題があります。
User.where(:id > 200)
そして
User.where("? > 200", :id)
両方とも失敗しました。
助言がありますか?
回答:
これを試して
User.where("id > ?", 200)
?
インライン化するよりもを使用するほうがよい理由はあります200
か?
私はこれをRails 4でテストしただけですが、where
ハッシュで範囲を使用してこの動作を実現する興味深い方法があります。
User.where(id: 201..Float::INFINITY)
SQLを生成します
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)
同じことを未満で行うことができます-Float::INFINITY
。
私は、SOの日付でこれを行うことについて尋ねる同様の質問を投稿しました。
>=
対 >
人々が掘り下げてコメントの会話に従う必要がないようにするために、ここにハイライトがあります。
上記の方法は、唯一の生成>=
クエリおよびません>
。この代替案を処理するには多くの方法があります。
離散数の場合
number_you_want + 1
上記のような戦略を使用できますが、私はユーザーに興味がありますがid > 200
、実際に探していid >= 201
ます。これは、関心のある単一の単位で増分できる整数および数値の場合は問題ありません。
数値を適切な名前の定数に抽出した場合、一目でこれを読んで理解するのが最も簡単な場合があります。
反転論理
x > y == !(x <= y)
チェーンを使用しないという事実を使用できます。
User.where.not(id: -Float::INFINITY..200)
SQLを生成する
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))
これは、読み取りに約1秒かかり、その理由を説明しますが、+ 1
戦略を使用できない非離散値または列に対しては機能します。
Arelテーブル
ファンシーになりたい場合は、を利用できますArel::Table
。
User.where(User.arel_table[:id].gt(200))
SQLを生成します
"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"
詳細は次のとおりです。
User.arel_table #=> an Arel::Table instance for the User model / users table
User.arel_table[:id] #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to `where`
このアプローチでは、興味のある正確な SQL が得られますが、Arelテーブルを直接使用する人は多くなく、面倒でわかりにくい場合があります。あなたとあなたのチームはあなたにとって何が最善かを知っています。
Rails 5以降では、日付を使用してこれを行うこともできます!
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
SQLを生成します
SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')
Ruby 2.6がリリースされると(2018年12月25日)、新しい無限範囲構文を使用できるようになります。代わりに201..Float::INFINITY
を書くだけで済みます201..
。詳細については、このブログ投稿をご覧ください。
where
マッチャーを使用してそれを行うことができるとは思わない。>
私が使用することをお勧め>= (number_you_want + 1)
簡単にするために。本当に>
クエリにしたい場合は、ARelテーブルにアクセスできます。継承することを、すべてのクラスActiveRecord
があるarel_table
返すゲッターメソッドArel::Table
、そのクラスのために。テーブルの列には、などの[]
メソッドを使用してアクセスしますUser.arel_table[:id]
。これは、Arel::Attributes::Attribute
呼び出しgt
て渡すことができるを返します200
。その後、これをに渡すことができますwhere
。例えばUser.where(User.arel_table[:id].gt(200))
。
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
。
WHERE (users.created_at >= '2016-04-09 14:31:15' AND users.created_at < #<Date::Infinity:0x00>)
(SOコメントのフォーマットではテーブル名と列名をバックティックで省略して)クエリが返されます。
より直感的な記述が必要な場合は、squeelと呼ばれる宝石があり、次のような指示を記述できます。
User.where{id > 200}
「中かっこ」文字{}とid
単なるテキストであることに注意してください。
Gemfileにsqueelを追加するだけです。
gem "squeel"
これにより、Rubyで複雑なSQLステートメントを作成するときに、生活が大幅に緩和される可能性があります。
別の空想の可能性は...
User.where("id > :id", id: 100)
この機能を使用すると、たとえば、複数の場所で置き換えたい場合に、より包括的なクエリを作成できます...
User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)
これは、多くの?
クエリを実行するよりも意味があります...
User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)
日付フィールドでこの問題がよく発生します(比較演算子が非常に一般的です)。
しっかりとしたアプローチだと私は信じているミハイの答えについてさらに詳しく説明します。
モデルに次のようなスコープを追加できます。
scope :updated_at_less_than, -> (date_param) {
where(arel_table[:updated_at].lt(date_param)) }
...そして、コントローラ、またはモデルを使用している場所:
result = MyModel.updated_at_less_than('01/01/2017')
...結合を使用したより複雑な例は次のようになります。
result = MyParentModel.joins(:my_model).
merge(MyModel.updated_at_less_than('01/01/2017'))
このアプローチの大きな利点は、(a)異なるスコープからクエリを作成できること、および(b)arel_tableがクエリ生成のその部分を処理するため、同じテーブルに2回結合するときにエイリアスの衝突を回避できることです。
より短い:
User.where("id > 200")
where("id > ?", 200)
構文)を使用してSQLインジェクションを回避したいと思います。これはそれを達成しません。