日付属性を持つActiveRecordモデルがあります。その日付属性を利用して、年、日、月ごとに検索することは可能ですか?
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
または、単にfind_by_date(2012-12-1)を実行できますか。
年、月、日の属性を作成しないようにしたいと思っていました。
「日付属性」が(完全なタイムスタンプではなく)日付であると仮定すると、単純なwhere
が「日付による検索」を提供します。
Model.where(:date_column => date)
find_by_date_column
は1つの結果しか得られないため、必要ありません。
extract
SQL関数を使用する年、月、日のクエリの場合:
Model.where('extract(year from date_column) = ?', desired_year)
Model.where('extract(month from date_column) = ?', desired_month)
Model.where('extract(day from date_column) = ?', desired_day_of_month)
ただし、SQLiteを使用している場合は、strftime
が何であるかわからないため、extract
をいじる必要があります。
Model.where("cast(strftime('%Y', date_column) as int) = ?", desired_year)
Model.where("cast(strftime('%m', date_column) as int) = ?", desired_month)
Model.where("cast(strftime('%d', date_column) as int) = ?", desired_day_of_month)
%m
および%d
形式指定子は、場合によって先頭にゼロを追加し、等価テストを混乱させる可能性があります。したがって、cast(... as int)
は、フォーマットされた文字列を数字にします。
ActiveRecordはデータベース間のすべての違いからあなたを保護しませんので、些細なことをしないとすぐに、独自の移植性レイヤーを構築する必要があります(ugいですが時には必要です)、データベースの限られたセットに結び付けます任意のデータベースで実行する必要があるものをリリースするか、またはRuby(非自明なデータ量に対しては非常識)ですべてのロジックを実行します。
大きなテーブルでは、年、月、および曜日のクエリはかなり遅くなります。一部のデータベースでは、関数の結果にインデックスを追加できますが、ActiveRecordはそれらを理解するには愚かすぎるため、それらを使用しようとすると大きな混乱を招きます。そのため、これらのクエリが遅すぎる場合は、回避しようとしている3つの列を追加する必要があります。
これらのクエリを頻繁に使用する場合は、クエリのスコープを追加できますが、 引数付きのスコープを追加する推奨方法 はクラスメソッドを追加するだけです:
スコープの引数を受け取るには、クラスメソッドを使用することをお勧めします。これらのメソッドは、関連オブジェクトで引き続きアクセスできます...
したがって、次のようなクラスメソッドがあります。
def self.by_year(year)
where('extract(year from date_column) = ?', year)
end
# etc.
データベースに依存しないバージョン...
def self.by_year(year)
dt = DateTime.new(year)
boy = dt.beginning_of_year
eoy = dt.end_of_year
where("published_at >= ? and published_at <= ?", boy, eoy)
end
MySQLの場合はこれを試してください
Model.where("MONTH(date_column) = 12")
Model.where("YEAR(date_column) = 2012")
Model.where("DAY(date_column) = 24")
モデル内:
scope :by_year, lambda { |year| where('extract(year from created_at) = ?', year) }
コントローラーで:
@courses = Course.by_year(params[:year])
これを行う最も簡単な方法はスコープだと思います:
scope :date, lambda {|date| where('date_field > ? AND date_field < ?', DateTime.parse(date).beginning_of_day, DateTime.parse(date).end_of_day}
次のように使用します。
Model.date('2012-12-1').all
これにより、送信する日付の開始日と終了日の間にdate_fieldを持つすべてのモデルが返されます。
これを試して:
Model.where("MONTH(date_column) = ? and DAY(date_column) = ?", DateTime.now.month, DateTime.now.day)
app/models/your_model.rb
scope :created_in, ->(year) { where( "YEAR( created_at ) = ?", year ) }
使用法
Model.created_in(1984)
これは別のものです:
def self.by_year(year)
where("published_at >= ? and published_at <= ?", "#{year}-01-01", "#{year}-12-31")
end
私にとってSQLiteでかなりうまく機能します。
私はBSBの答えが好きですが、スコープとして
scope :by_year, (lambda do |year|
dt = DateTime.new(year.to_i, 1, 1)
boy = dt.beginning_of_year
eoy = dt.end_of_year
where("quoted_on >= ? and quoted_on <= ?", boy, eoy)
end)
以下に示す別の短いスコープ:
class Leave
scope :by_year, -> (year) {
where(date:
Date.new(year).beginning_of_year..Date.new(year).end_of_year)
}
end
スコープを呼び出します:
Leave.by_year(2020)
extract
メソッドは必要ありません。これはpostgresqlの魅力のように機能します。
text_value = "1997" # or text_value = '1997-05-19' or '1997-05' or '05', etc
sql_string = "TO_CHAR(date_of_birth::timestamp, 'YYYY-MM-DD') ILIKE '%#{text_value.strip}%'"
YourModel.where(sql_string)