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 Studio 利用者の声
「Beekeeper Studioで以前のSQLワークフローを完全に置き換えました。高速で直感的で、データベース作業がまた楽しくなりました。」
「多くのデータベースGUIを試してきましたが、Beekeeperは機能とシンプルさのバランスが完璧です。とにかくちゃんと動きます。」