Rails5 でよく使われる Active Record のクエリをまとめました。
find
主キーで検索します。
User.find(100)
=> SELECT users
.* FROM users
WHERE users
.id
= 100 LIMIT 1
# 複数指定
User.find([100, 101])
=> SELECT users
.* FROM users
WHERE users
.id
IN (100, 101)
データが1件も取得できなかった場合は ActiveRecord::RecordNotFound でエラーになります。
take
指定した数のレコードを取得します。
# デフォルトは1件
User.take
=> SELECT users
.* FROM users
LIMIT 1
User.take(5)
=> SELECT users
.* FROM users
LIMIT 5
1件もない場合に例外(ActiveRecord::RecordNotFound)を起こす場合は ! をつけます。
User.take!
=> SELECT users
.* FROM users
LIMIT 1
first / second / third... / last
first: 主キーの昇順でソートして一番最初のレコードを返します。
last: 主キーの降順でソートして一番最初のレコードを返します。
User.first
=> SELECT users
.* FROM users
ORDER BY users
.id
ASC LIMIT 1
引数でとってくる数を指定できます。
User.first(3)
=> SELECT users
.* FROM users
ORDER BY users
.id
ASC LIMIT 3
1件もない場合に例外(ActiveRecord::RecordNotFound)を起こす場合は ! をつけます。
second, thirdなどで何番目のデータをとってくるか指定できます。
find_by
条件に合致したレコードを1件取得します。
# idで指定
User.find_by(id: 100)
=> SELECT users
.* FROM users
WHERE users
.id
= 100 LIMIT 1
# nameで指定
User.find_by(name: 'taro')
=> SELECT users
.* FROM users
WHERE users
.name
= 'taro' LIMIT 1
# 複数指定
User.find_by(name: 'taro', email: 'test@example.com')
=> SELECT users
.* FROM users
WHERE users
.name
= 'taro' AND users
.email
= 'test@example.com' LIMIT 1
1件もない場合に例外(ActiveRecord::RecordNotFound)を起こす場合は ! をつけます。
all / find_each / find_in_batches
すべてのレコードを取得します。
User.all
=> SELECT users
.* FROM users
レコード数が多いとメモリが足りなくなるので、その場合は find_each や find_in_batches でデータを何件かに分けて取得するようにします(バッチ処理)。
# デフォルトでは1000件ずつ取得
User.find_each do |user|
p user.id
end
取得するデータ数を指定する場合は batch_size を使用します。
# 100件ずつ取得
User.find_each(batch_size: 100) do |user|
p user.id
end
バッチ処理を開始・終了する主キーを指定する場合は start、finish を使用します。
# id が100以上のデータ
User.find_each(start: 100) do |user|
p user.id
end
# id が100以上200以下のデータ
User.find_each(start: 100, finish: 200) do |user|
p user.id
end
バッチ処理をする引数を配列で扱いたい場合は find_in_batches を使用します。
# ブロック引数の users は、user オブジェクトが1000個入った配列
User.find_in_batches do |users|
p users
end
find_in_batches も同様に batch_size、start、finish が使用できます。
where
指定した条件に合致するレコードを取得します。
User.where(name: 'taro')
=> SELECT users
.* FROM users
WHERE users
.name
= 'taro'
カラム名は文字列、ロケット記法でも指定できます。
User.where('name' => 'taro')
=> SELECT users
.* FROM users
WHERE users
.name
= 'taro'
同カラムで条件値を複数指定する場合は配列にします。
User.where(name: ['taro', 'ziro'])
=> SELECT users
.* FROM users
WHERE users
.name
IN ('taro', 'ziro')
否定を指定する場合は where.not を使用します。
User.where.not(name: 'taro')
=> SELECT users
.* FROM users
WHERE (users
.name
!= 'taro')
条件値が動的に変わる場合は ? か、名前を指定したい場合は :colume_name を使います。
name = "taro"
email = "test@example.com"
User.where("name = ?", name)
User.where("name = ? and email = ?", name, email)
name = "taro"
email = "test@example.com"
User.where("name = :name and email = :email", name: name, email: email)
複数の条件のうち、1つでもマッチしたものを取得する場合は where.or を使用します。
User.where(name: 'taro').or(User.where(email: 'test@example.com'))
=> SELECT users
.* FROM users
WHERE (users
.name
= 'taro' OR users
.email
= 'test@example.com')
条件に範囲を指定する場合は .. を使用します。
User.where(created_at: (Time.now.midnight - 1.day)..Time.now.midnight)
=> SELECT users
.* FROM users
WHERE (users
.created_at
BETWEEN '2015-01-06 15:00:00' AND '2015-01-07 15:00:00')
order
並び順を指定します。
# created_atの昇順
User.order(:created_at)
=> SELECT users
.* FROM users
ORDER BY users
.created_at
ASC
# 文字列でも指定可能
User.order("created_at")
# 昇順
User.order(created_at: :asc)
User.order("created_at asc")
# 降順
User.order(created_at: :desc)
User.order("created_at desc")
# 複数指定
User.order(name: :asc, created_at: :desc)
User.order("name asc, created_at desc")
select
指定したカラム名を取得します。
User.select(:name)
=> SELECT users
.name
FROM users
同カラムでユニークなレコードのみ取得したい場合は distinct を使用します。
User.select(:name).distinct
limit / offset
limit は取得件数、offset は何番目のデータから取得するかを指定します。配列のインデックスと同じで、1件目は「0」を指定します。
# 5件取得
User.limit(5)
=> SELECT users
.* FROM users
LIMIT 5
# 11番目から5件取得
User.limit(5).offset(10)
=> SELECT users
.* FROM users
LIMIT 5 OFFSET 10
find_or_create_by
あれば取得し、なければ新規作成します。
User.find_or_create_by(name: 'taro')
新規作成する際に他のカラムに値を設定したい場合は create_with もしくはブロックを使用します。
User.create_with(email: 'taro@example.com').find_or_create_by(name: 'taro')
# ブロックの場合
User.find_or_create_by(name: 'taro') do |user|
user.email = 'taro@example.com'
end
新規作成する際にバリデーションでエラーになった場合に例外を発生させるには ! をつけます。
find_or_initialize_by
あれば取得し、なければ初期化します。
User.find_or_initialize_by(name: 'taro')
pluck
特定のカラムのリストを配列で返します。
User.pluck(:id)
=> SELECT users
.id
FROM users
# 複数指定
User.pluck(:id, :name)=> SELECT users
.id
, users
.name
FROM users
ids
idのリストを配列で返します。
User.ids
=> SELECT users
.id
FROM users
exists?
レコードが存在するかどうかを true/false で返します。
User.exists?(1) # デフォルトは id
User.exists?(name: 'taro')
User.where(name: 'taro').exists?
count
レコード数を返します。
User.count
=> SELECT COUNT(*) FROM users
# 条件句つき
User.where(name: 'taro').count
=> SELECT COUNT(*) FROM users
WHERE users
.name
= 'taro'
average
特定カラムの平均値を取得します。
Item.average(:price)
=> SELECT AVG(items
.price
) AS avg_id FROM items
minimum
特定カラムの最小値を取得します。
Item.minimum(:price)
=> SELECT MIN(items
.price
) AS min_id FROM items
maximum
特定カラムの最大値を取得します。
Item.maximum(:price)
=> SELECT MAX(items
.price
) AS max_id FROM items
sum
特定カラムの合計値を取得します。
Item.sum(:price)
=> SELECT SUM(items
.price
) AS sum_id FROM items
readonly
読み込み専用として取得します。
user = User.readonly.first
user.name = "ziro"
user.save # エラー
group
特定のカラムをグルーピングします。
他のカラムの件数を取得する場合
Item.group(:name).count
=> SELECT COUNT(*) AS count_all, name AS name FROM items
GROUP BY name
他のカラムの平均値を出す場合
Item.group(:name).average(:price)
=> SELECT AVG(items
.price
) AS average_price, name AS name FROM items
GROUP BY name
他のカラムの合計値を出す場合
Item.group(:name).sum(:price)
=> SELECT SUM(items
.price
) AS sum_price, name AS name FROM items
GROUP BY name
グルーピングする時に条件を追加する場合は having を使用します。
Item.group(:name).having(name: "apple").average(:price)
=> SELECT AVG(items
.price
) AS average_price, name AS name FROM items
GROUP BY name HAVING items
.name
= 'apple'
group_by(&:カラム名)
特定のカラムでモデルをグルーピングします。
Item.group_by(:&name)
find_by_sql
検索に生のSQLを使います。返り値は配列です。
User.find_by_sql('select * from users where id = 1')
select_all
検索に生のSQLを使います。返り値はハッシュです。
User.connection.select_all('select * from users where id = 1')
to_sql
ActiveRecord_Relation のメソッドで、発行したSQLの内容を確認することができます。
User.where(1).to_sql
=> "SELECT users
.* FROM users
WHERE (1)"
explain
ActiveRecord_Relation のメソッドで、発行したSQLの内容を詳細に確認することができます。
User.where(1).explain
=> EXPLAIN for: SELECT users
.* FROM users
WHERE (1)
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 106 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
当社で開発した予定とタスクを同時に管理できるiOSアプリ「My Schedule - マイスケジュール -」をリリースしました。ダウンロード&評価のほどよろしくお願いいたします。