Railsにおけるクエリ文

Railsにおいてコンソールでクエリ文を叩くと、ログにSQL文も表示される。これもしっかりみてどのような動きをしているのか観察しよう。

参考

orderメソッド

SQLのORDER BY節を作る。 指定したカラムの昇順(ASC)か降順(DESC)で並び替える。

@users = User.order(id: :desc)

# idが10, 9, 8....である順にレコードが並び替えられる。
=>
[<User id: 10, name: trump, country: usa>, <User id: 9, name: abe, country: japan>...
 <User id: 1, name: putin, country: russia>]


joinsメソッド

SQLのJOIN節(INNER JOIN)をつくる。 引数のモデルと内部結合出来る。

@writers = User.joins(:articles)

# articleが持つuserのidに対応する、全てのユーザーが表示される。
=>
[<User id: 10, name: honda, media: asahi>, 
 <User id: 8, name: jimmy, media: foxnews>,
 <User id: 10, name: honda, media: asahi>
 <User id: 4, name: chen, media: cctv>.....]


Category.joins(:articles)

これは以下のSQL文に等しい。

SELECT categories.* FROM categories
  INNER JOIN articles ON articles.category_id = categories.id


groupメソッド

SQLにおけるGROUP BY句に該当。

Order.select("date(created_at) as ordered_date, sum(price) as total_price").group("date(created_at)")

これは以下のSQL文に等しい。

SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
GROUP BY date(created_at)


Havingメソッド

SQLにおけるGROUP BYフィールドで条件を指定する場合にHAVING句を使用するが、それに該当する。

Order.select("date(created_at) as ordered_date, sum(price) as total_price").
  group("date(created_at)").having("sum(price) > ?", 100)

上の文は以下と等しい。

SELECT date(created_at) as ordered_date, sum(price) as total_price
FROM orders
GROUP BY date(created_at)
HAVING sum(price) > 100


left_outer_joinsメソッド

関連レコードがあるかどうかにかかわらずレコードのセットを取得したいときに使う。外部結合。

Author.left_outer_joins(:posts).distinct.select('authors.*, COUNT(posts.*) AS posts_count').group('authors.id')

以下は上に同じ。

SELECT DISTINCT authors.*, COUNT(posts.*) AS posts_count FROM "authors"
LEFT OUTER JOIN posts ON posts.author_id = authors.id GROUP BY authors.id


pluckメソッド

数としてカラム名のリストを与えると、指定したカラムの値の配列を、対応するデータ型で返す。Productモデルがあったとして、nameカラムの中身を確認したい場合はこのメソッドが有効である。

Product.pluck(:name)
=> ["Ruby on Rails Tote",
 "Ruby on Rails Bag",
 "Ruby on Rails Baseball Jersey",
 "Ruby on Rails Jr. Spaghetti",
 "Ruby on Rails Ringer T-Shirt",
 "Ruby Baseball Jersey",
 "Apache Baseball Jersey",
 "Ruby on Rails Mug",
 "Ruby on Rails Stein"]

Product.pluck(:id,:name)
=> [[1, "Ruby on Rails Tote"],
 [2, "Ruby on Rails Bag"],
 [3, "Ruby on Rails Baseball Jersey"],
 [4, "Ruby on Rails Jr. Spaghetti"],
 [5, "Ruby on Rails Ringer T-Shirt"],
 [6, "Ruby Baseball Jersey"],
 [7, "Apache Baseball Jersey"],
 [8, "Ruby on Rails Mug"],
 [9, "Ruby on Rails Stein"]]


平均

テーブルに含まれる特定の数値の平均を得るには、そのテーブルを持つクラスに対してaverageメソッドを呼び出す。返される値は、そのカラムの平均値であり、通常3.14159265のような浮動小数点になる。

Client.average("orders_count")


最小

テーブルに含まれるカラムの最小値を得るには、そのテーブルを持つクラスに対してminimumメソッドを呼び出す。

Client.minimum("age")


最大

テーブルに含まれるカラムの最小値を得るには、そのテーブルを持つクラスに対してmaximumメソッドを呼び出す。

Client.maximum("age")


EXPLAINを実行する

explainの実行で、実行計画を見ることができる。

User.where(id: 1).joins(:articles).explain


メソッドチェーン

例文1

Person
  .select('people.id, people.name, comments.text')
  .joins(:comments)
  .where('comments.created_at > ?', 1.week.ago)

以下は上に同じ。

SELECT people.id, people.name, comments.text
FROM people
INNER JOIN comments
  ON comments.person_id = people.id
WHERE comments.created_at > '2015-01-01'


例文2

Person
  .select('people.id, people.name, companies.name')
  .joins(:company)
  .find_by('people.name' => 'John') # 名を指定

以下は上に同じ。

SELECT people.id, people.name, companies.name
FROM people
INNER JOIN companies
  ON companies.person_id = people.id
WHERE people.name = 'John'
LIMIT 1


直にSQLを書く

独自のSQLを使用してレコードを検索したい場合、find_by_sqlメソッドを使用できる。このfind_by_sqlメソッドは、オブジェクトの配列を1つ返す。クエリがレコードを1つしか返さなかった場合にも配列が返される。

Client.find_by_sql("SELECT * FROM clients
  INNER JOIN orders ON clients.id = orders.client_id
  ORDER BY clients.created_at desc")
# =>  [
#   #<Client id: 1, first_name: "Lucas" >,
#   #<Client id: 2, first_name: "Jan" >,
#   ...
# ]