🧚 お知らせ!Beekeeper Studioは高速でモダンなオープンソースのデータベースGUIです ダウンロード
2024年9月12日 著者: Matthew Rathbone

Active RecordでSQL関数を使う

ほとんどのSQLデータベースには、日付の一部を取り出す関数が用意されています。たとえばPostgreSQLではEXTRACT(DOW FROM date)を使います。DOWは「day of the week(曜日)」の略で、0(日曜日)から6(土曜日)までの値を返します。

created_atカラムを持つTaskモデルを例に考えます。目的は平日に作成されたレコードだけを取得することです。これをActive Recordのクエリ機能で実現します。

# app/models/task.rb
class Task < ApplicationRecord
  scope :weekdays_only, -> { where("EXTRACT(DOW FROM created_at) BETWEEN 1 AND 5") }
end

解説:

  • EXTRACT(DOW FROM created_at): created_atタイムスタンプから曜日を取り出します。
  • BETWEEN 1 AND 5: 月曜日から金曜日までに絞り込みます。

Active RecordでRubyのDateメソッドを使う

RubyのDateメソッドだけを使いたい場合は、データベースからレコードを取得した後に絞り込むようコードを変更できます。ただし、大きなデータセットでは効率的ではありません。

# app/models/task.rb
class Task < ApplicationRecord
  def self.weekdays_only_ruby
    all.select { |task| task.created_at.on_weekday? }
  end
end

解説:

  • この方法では、まずデータベースからすべてのレコードを取得し、その後Rubyのon_weekday?メソッドで絞り込みます。
  • task.created_at.on_weekday?: created_atタイムスタンプをRubyのDateオブジェクトに変換し、平日(月曜日から金曜日)かどうかを判定します。

使用例:

Task.weekdays_only_ruby

注意: この方法は、まずデータベースからすべてのレコードを取得してからメモリ上で処理するため、非効率になる場合があります。小さなデータセット向けです。大きなデータセットを扱う場合は、SQLによる方法のほうがはるかに効率的です。

Active Recordで条件を組み合わせる

平日に加えて、ステータスなど特定の条件でもレコードを絞り込みたい場合があります。これはスコープをチェーンすることで実現できます:

# app/models/task.rb
class Task < ApplicationRecord
  scope :weekdays_only, -> { where.not("EXTRACT(DOW FROM created_at) IN (0, 6)") }
  scope :completed, -> { where(status: 'completed') }
end

使用例:

Task.weekdays_only.completed

異なるタイムゾーンをまたいだクエリ

タイムゾーンを扱う場合は、created_atタイムスタンプが適切に変換されるようにしてください。正確に比較するには、SQLのAT TIME ZONE句を使います。

# app/models/task.rb
class Task < ApplicationRecord
  scope :weekdays_only_in_timezone, ->(timezone) {
    where("EXTRACT(DOW FROM created_at AT TIME ZONE ?) BETWEEN 1 AND 5", timezone)
  }
end

使用例:

Task.weekdays_only_in_timezone('UTC')

他のデータベースへの対応

SQLデータベースによって、日付の抽出に使う関数が異なる場合があります:

  • MySQL: DAYOFWEEK(created_at)
  • SQLite: strftime('%w', created_at)

使用しているデータベースに合わせてクエリを調整してください:

# Example for MySQL
scope :weekdays_only, -> { where("DAYOFWEEK(created_at) BETWEEN 2 AND 6") }

これらのスコープを実装すると、Task.weekdays_onlyをクエリすることで、平日に作成されたタスクだけのコレクションが得られます。例を示します:

tasks = Task.weekdays_only
tasks.each do |task|
  puts task.created_at
end

出力:

2024-08-26 10:30:00 UTC  # Monday
2024-08-27 11:45:00 UTC  # Tuesday
2024-08-28 09:00:00 UTC  # Wednesday

まとめ

SQL関数やRubyのメソッドで日付の一部を取り出せば、Active Recordの結果を平日のみに絞り込むのは簡単です。

こちらの記事もおすすめです:

Beekeeper Studioは無料のオープンソースのデータベースGUIです

これまで使った中で最高のSQLクエリ&エディタツールです。データベースの管理に必要なものがすべて揃っています。 - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studioは高速で直感的、そして使いやすいツールです。多数のデータベースに対応し、Windows、Mac、Linuxで快適に動作します。

BeekeeperのLinux版は100%フル機能。手抜きも機能の妥協も一切ありません。

Beekeeper Studio 利用者の声

★★★★★
「Beekeeper Studioで以前のSQLワークフローを完全に置き換えました。高速で直感的で、データベース作業がまた楽しくなりました。」
— Alex K.、データベース開発者
★★★★★
「多くのデータベースGUIを試してきましたが、Beekeeperは機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」
— Sarah M.、フルスタックエンジニア