RailsでいろんなSQLを発行する

下記の記事がよくまとまっていたので引用しつつ。

Rails(ActiveRecord)で自在にSQLを書く手段いろいろ | Takakisan

to_sqlによるSQL埋め込み

to_sql でSQL文字列化して joins とか where に埋め込むテク。

ちょっとテクニカルで読みにくくなるものの、生SQL書くよりは全然読みやすく、パフォーマンス向上のためならこれくらいは許されるかな、のレベル。

exists_sql =
  Purchase.select(1)
          .where('users.id = purchases.user_id')
          .where(shop_id: 5)
          .to_sql
users = User.where("exists (#{exists_sql})")
latest_purchases =
  Purchase.where(
    'not exists ('\
    'select 1 from purchases sub '\
    'where sub.user_id = purchases.user_id '\
    'and sub.created_at > purchases.created_at'\
    ')'
  )
users =
  User.select(:id, :name, 'latest_purchases.shop_id latest_purchase_shop_id')
      .joins("inner join (#{latest_purchases.to_sql}) latest_purchases "\
             'on users.id = latest_purchases.user_id')

fromによるサブクエリ化

from を使ってトリッキーにレコードfetchするとき。

with_rownum =
  Purchase.select('*',
                  'row_number() '\
                  'over (partition by user_id order by created_at desc) rownum')
purchases =
  Purchase.select('*')
          .from(with_rownum, :with_rownum)
          .where('with_rownum.rownum <= ?', 3)

公式ドキュメントだとこんな例だったりする。

Topic.select('title').from(Topic.approved)
# SELECT title FROM (SELECT * FROM topics WHERE approved = 't') subquery

ref. ActiveRecord::QueryMethods | RailsDoc(β)