現在、Railsブロンズ試験を受験してみようと思い、RubyonRails5アプリケーションプログラミングという本で勉強中なので、頭の整理も兼ねて学んだことをまとめてみるφ(..)
Ruby on Rails 5アプリケーションプログラミング
- 作者: 山田祥寛
- 出版社/メーカー: 技術評論社
- 発売日: 2017/04/14
- メディア: 大型本
- この商品を含むブログを見る
今回はモデルの検索について主要なメソッドをまとめてみました・ω・
- モデルの検索処理まとめ
- 主キーによる検索:findメソッド
- 任意キーによる検索:find_byメソッド
- 基本的な条件式を設定する:whereメソッド
- 条件に合致しないレコードを検索する:notメソッド
- OR条件で複数条件を設定する:orメソッド
- 取得結果を並び変える:orderメソッド
- 取得する項目を指定する:selectメソッド
- 重複したレコードを削除する:distinctメソッド
- レコードの取得件数を制御する:limitメソッド・offsetメソッド
- データの集計を行う:groupメソッド
- 集計後の結果に検索条件を設定する:havingメソッド
- 特定項目の平均値・最小値・最大値・合計値を取得する:averageメソッド・minimumメソッド・maximumメソッド・sumメソッド
- 生のSQLを使って検索を行う:find_by_sqlメソッド
モデルの検索処理まとめ
主キーによる検索:findメソッド
find
メソッドは、主キーによるレコードの検索を行います。
取得結果は主キー指定の場合はモデルのインスタンス、複数の主キーを指定した場合は、モデルのインスタンスの配列が返却されます。
# 主キーによる検索 Model.find(1) #=> SELECT "models".* FROM "models" WHERE "models"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] # 複数の主キーによる検索 Model.find([1, 2, 3]) #=> LECT "models".* FROM "models" WHERE "models"."id" IN (1, 2, 3)
任意キーによる検索:find_byメソッド
find_by
メソッドは、任意の項目をキーとして検索を行います。
取得結果として検索条件に合致した最初の一件を返却します。
また複数の検索キーが引数に設定された場合は、複数の検索キー(AND条件)で結果を取得します。
# タイトルをキーとして検索 Model.find_by(title: "hoge") #=> SELECT "models".* FROM "models" WHERE "models"."title" = ? LIMIT ? [["title", "hoge"], ["LIMIT", 1]] # タイトルと内容をキーとして検索 Model.find_by(title: "hoge").find_by(content: "fuga") #=> SELECT "models".* FROM "models" WHERE "models"."title" = ? AND "models"."content" = ? LIMIT ? [["title", "hoge"], ["content", "fuga"], ["LIMIT", 1]]
基本的な条件式を設定する:whereメソッド
where
メソッドは、引数に条件を設定し、与えられた条件に合致するレコードを返却します。
find_by
メソッドと一見似ていますが、where
メソッドは、条件に合致する全てのレコードを返却します。
また、プレースホルダー?
を使い任意の値を条件式に埋め込むことが出来ます。
※取得結果が1件だったとしてもActiveRecord::Relation
で返却されるため注意が必要です。
# タイトルがhogeかつ本文がfugaのレコードを検索 # hashで複数条件を与えた場合はfind_byメソッドと同様にAND条件となる。 Model.where(title: "hoge", content: "fuga") #=> SELECT "models".* FROM "models" WHERE "models"."title" = ? AND "models"."content" = ? LIMIT ? [["title", "hoge"], ["content", "fuga"], ["LIMIT", 11]] # 金額が1000以上のレコードを検索 Model.where('price >= ?', 1000) #=> SLECT "models".* FROM "models" WHERE (price >= 1000) LIMIT ? [["LIMIT", 11]]
条件に合致しないレコードを検索する:notメソッド
not
メソッドを使うことで、where
メソッドで指定した条件に合致しないレコードを取得することが出来ます。
# タイトルがhogeじゃないレコードを検索 Model.where.not(title: "hoge") #=> SELECT "models".* FROM "models" WHERE "models"."title" != ? LIMIT ? [["title", "hoge"], ["LIMIT", 11]]
OR条件で複数条件を設定する:orメソッド
or
メソッドは与えられた条件式をOR条件(または)として加えることが出来ます。
ただし、加えられるのは同一モデルに対するwhere
メソッドのみです。
# タイトルがhogeまたは本文がfugaのレコードを検索 Model.where(title: "hoge").or(Model.where(content: "fuga")) #=> SELECT "models".* FROM "models" WHERE ("models"."title" = ? OR "models"."content" = ?) LIMIT ? [["title", "hoge"], ["content", "fuga"], ["LIMIT", 11]]
取得結果を並び変える:orderメソッド
order
メソッドに項目とソート順を与えることで取得結果の並び替えることが出来ます。
項目とソート順は複数与え、複数項目での並び替えを行うことも可能です。
# タイトルの昇順で並び変える Model.order(title: :asc) #=> SELECT "models".* FROM "models" ORDER BY "models"."title" ASC LIMIT ? [["LIMIT", 11]] # タイトルの降順で並び変える Model.order(title: :desc) #=> SELECT "models".* FROM "models" ORDER BY "models"."title" DESC LIMIT ? [["LIMIT", 11]] # 価格の降順、タイトルの昇順で並び変える Model.order(price: :desc, title: :asc) # => LECT "models".* FROM "models" ORDER BY "models"."price" DESC, "models"."title" ASC LIMIT ? [["LIMIT", 11]]
取得する項目を指定する:selectメソッド
select
メソッドを用いることで特定の項目のみを取得することが出来ます。
引数を複数与えることで、複数の項目を指定することも可能です。
# 全てのモデルのタイトルを取得する Model.select(:title) #=> SELECT "models"."title" FROM "models" LIMIT ? [["LIMIT", 11]] # 全てのモデルのタイトルと価格を取得する Model.select(:title, :price) #=> SELECT "models"."title", "models"."price" FROM "models" LIMIT ? [["LIMIT", 11]]
重複したレコードを削除する:distinctメソッド
distinct
メソッドを使うことで取得結果から重複したレコードを削除することが出来ます。
# モデルに設定されているジャンルの一覧を重複なしで取得 Model.select(:genre).distinct #=> SELECT DISTINCT "models"."genre" FROM "models" LIMIT ? [["LIMIT", 11]]
レコードの取得件数を制御する:limitメソッド・offsetメソッド
limit
メソッドを使用することで最大取得件数を制限することが出来ます。
また、offset
メソッドを使用することで、取得開始位置を指定することが出来ます。
# モデルを最大3件取得する Model.limit(3) # => SELECT "models".* FROM "models" LIMIT ? [["LIMIT", 3]] # モデルを10件目から10件取得する # offsetを指定する際は先頭行が0となるため注意 Model.offset(10).limit(10) # => SELECT "models".* FROM "models" LIMIT ? OFFSET ? [["LIMIT", 10], ["OFFSET", 10]]
データの集計を行う:groupメソッド
group
メソッドを使用することで特定のキーで結果をグルーピングし、データの集計を行うことが出来ます。
# ジャンル別の最大価格を取得する Model.select('genre, MAX(price) AS max_price').group(:genre) # => SELECT genre, MAX(price) as max_price FROM "models" GROUP BY "models"."genre"
集計後の結果に検索条件を設定する:havingメソッド
having
メソッドは、集計後の結果に対して条件を設定し絞込を行うことが出来ます。
# ジャンル別の最大価格が10000以上のものだけを取得する Model.select('genre, MAX(price) AS max_price').group(:genre).having('MAX(price) >= ?', 10000) # => SELECT genre, MAX(price) as max_price FROM "models" GROUP BY "models"."genre" HAVING (MAX(price) >= 10000) LIMIT ? [["LIMIT", 11]]
特定項目の平均値・最小値・最大値・合計値を取得する:averageメソッド・minimumメソッド・maximumメソッド・sumメソッド
平均・最小・最大・合計といった集計でよく使いそうなものは、メソッドとして定義されています。
これらのメソッドはwhere
メソッドに続けて記述することによって、検索結果に適用することも出来ます。
# 価格の平均値を取得 Model.average(:price) # => SELECT AVG("models"."price") FROM "models" # 価格の最小値を取得 Model.minimum(:price) # => SELECT MIN("models"."price") FROM "models" # 価格の最大値を取得 Model.maximum(:price) # => SELECT MAX("models"."price") FROM "models" # 価格の合計値を取得 Model.sum(:price) # => SELECT SUM("models"."price") FROM "models" # 特定ジャンルの平均価格を取得 Model.where(genre: "hoge").average(:price) # => SELECT AVG("models"."price") FROM "models" WHERE "models"."genre" = ? [["genre", "hoge"]]
生のSQLを使って検索を行う:find_by_sqlメソッド
どうしても生のSQLで検索を行いたい場合は、find_by_sqlメソッドを使用します。
※SQLの構文はDBMSに依存するためDBMS変更時に不具合を誘発する可能性があるため注意してください。
# 特定ジャンルのレコードを取得 Model.find_by_sql(['SELECT * FROM models WHERE genre = ?', 'hoge']) # => SELECT * FROM models WHERE genre = 'hoge'
以上です!
また何かあれば追記しようと思いますφ(..)