😇

RailsでSQLを操作してみようーー!!

に公開

RailsSQL実行用メソッド 完全ガイド

Railsでデータベース操作を行う際、ActiveRecordが便利ですが、パフォーマンスが必要な場面や複雑なクエリでは生SQLを使いたいケースがあったので、本記事では、実務でよく使われる生SQL実行用メソッドと、それに対応するActiveRecordの書き方を20パターン紹介します。

基本知識

主要な生SQL実行メソッド

  • execute: 戻り値なし、INSERT/UPDATE/DELETE用
  • connection.execute: 結果を返す、SELECT用
  • connection.select_all: ハッシュ配列で結果を返す
  • connection.select_value: 単一値を返す

1. 基本的なCRUD操作

1. データ挿入

# 生SQL
execute "INSERT INTO users (name, email) VALUES ('John', 'john@example.com')"

# ActiveRecord
User.create(name: 'John', email: 'john@example.com')

2. データ更新

# 生SQL
execute "UPDATE users SET name = 'Jane' WHERE id = 1"

# ActiveRecord
User.find(1).update(name: 'Jane')
# または
User.where(id: 1).update_all(name: 'Jane')

3. データ削除

# 生SQL
execute "DELETE FROM users WHERE age < 18"

# ActiveRecord
User.where('age < ?', 18).delete_all

4. データ取得

# 生SQL
connection.execute("SELECT * FROM users WHERE age > 20")

# ActiveRecord
User.where('age > ?', 20)

2. テーブル構造変更(マイグレーション)

5. カラム追加

# 生SQL
execute "ALTER TABLE users ADD COLUMN phone VARCHAR(255)"

# ActiveRecord
add_column :users, :phone, :string

6. カラム削除

# 生SQL
execute "ALTER TABLE users DROP COLUMN phone"

# ActiveRecord
remove_column :users, :phone

7. インデックス追加

# 生SQL
execute "CREATE INDEX index_users_on_email ON users(email)"

# ActiveRecord
add_index :users, :email

8. インデックス削除

# 生SQL
execute "DROP INDEX index_users_on_email"

# ActiveRecord
remove_index :users, :email

3. 制約操作

9. NOT NULL制約追加

# 生SQL
execute "ALTER TABLE users ALTER COLUMN email SET NOT NULL"

# ActiveRecord
change_column_null :users, :email, false

10. 外部キー追加

# 生SQL
execute "ALTER TABLE posts ADD CONSTRAINT fk_posts_users FOREIGN KEY (user_id) REFERENCES users(id)"

# ActiveRecord
add_foreign_key :posts, :users

11. 外部キー削除

# 生SQL
execute "ALTER TABLE posts DROP FOREIGN KEY fk_posts_users"

# ActiveRecord
remove_foreign_key :posts, :users

4. 集計・複雑なクエリ

12. 集計クエリ

# 生SQL
connection.execute("SELECT COUNT(*) as count, status FROM orders GROUP BY status")

# ActiveRecord
Order.group(:status).count

13. サブクエリを使った更新

# 生SQL
execute "UPDATE users SET total_orders = (SELECT COUNT(*) FROM orders WHERE orders.user_id = users.id)"

# ActiveRecord
User.left_joins(:orders).group('users.id').update_all('total_orders = COUNT(orders.id)')

14. 複数テーブルからの更新

# 生SQL
execute "UPDATE users u JOIN profiles p ON u.id = p.user_id SET u.name = p.full_name"

# ActiveRecord
User.joins(:profile).update_all('users.name = profiles.full_name')

15. CASE文を使った更新

# 生SQL
execute "UPDATE orders SET status = CASE WHEN amount > 1000 THEN 'premium' ELSE 'standard' END"

# ActiveRecord
Order.update_all("status = CASE WHEN amount > 1000 THEN 'premium' ELSE 'standard' END")

5. 実務で頻発する高度な操作

16. バルクインサート

# 生SQL
execute "INSERT INTO logs (message, created_at) VALUES ('msg1', NOW()), ('msg2', NOW())"

# ActiveRecord(Rails 6以降)
Log.insert_all([{message: 'msg1'}, {message: 'msg2'}])

17. TRUNCATE(全データ削除)

# 生SQL
execute "TRUNCATE TABLE temp_data"

# ActiveRecord(完全ではないが類似)
TempData.delete_all

18. シーケンスリセット

# 生SQL(PostgreSQL)
execute "ALTER SEQUENCE users_id_seq RESTART WITH 1"

# ActiveRecord
connection.reset_pk_sequence!(:users)

19. 条件付き一括更新

# 生SQL
execute "UPDATE products SET price = price * 0.9 WHERE category_id IN (1,2,3)"

# ActiveRecord
Product.where(category_id: [1,2,3]).update_all('price = price * 0.9')

20. JSON操作(PostgreSQL)

# 生SQL
execute "UPDATE users SET settings = jsonb_set(settings, '{theme}', '\"dark\"')"

# ActiveRecord(生SQLの方が推奨)
User.update_all("settings = jsonb_set(settings, '{theme}', '\"dark\"')")

使い分けのポイント

生SQLを使うべき場面

  • 大量データの処理でパフォーマンスが重要
  • 複雑なJOINやサブクエリが必要
  • データベース固有の機能を使いたい
  • マイグレーションでの細かい制御

ActiveRecordを使うべき場面

  • 通常のCRUD操作
  • 可読性を重視したい
  • データベースに依存しないコードを書きたい
  • Railsのバリデーションやコールバックを活用したい

まとめ

生SQLとActiveRecordはそれぞれ適した場面があります。基本的にはActiveRecordを使い、パフォーマンスや複雑性の要求に応じて生SQLを選択するのがベストプラクティスです。

特にマイグレーションでは、executeメソッドを使った生SQLが重宝するケースが多いので、ぜひ覚えておきましょう!!!

Discussion