ActiveRecord在date字段中按年,日或月查找
我有一个具有date属性的ActiveRecord模型。 是否有可能利用该date属性按年,日和月查找:
Model.find_by_year(2012) Model.find_by_month(12) Model.find_by_day(1)
或者只是可以find_by_date(2012-12-1)。
我希望能避免创build年,月和日属性。
假设你的“date属性”是一个date(而不是一个完整的时间戳),那么一个简单的where
会给你你的“按date查找”:
Model.where(:date_column => date)
你不想要find_by_date_column
因为这样做最多只能得到一个结果。
对于您想要使用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
格式说明符将在某些情况下添加前导零,并且可能会混淆相等性testing,因此将cast(... as int)
强制格式化的string转换为数字。
ActiveRecord不会保护你免受数据库之间的所有差异的影响,所以一旦你做了任何不重要的事情,你必须build立你自己的可移植性层(丑陋但有时是必需的),把自己绑定到一个有限的数据库集(除非你发布了一些必须在任何数据库上运行的东西),或者在Ruby中执行所有的逻辑(对于任何不重要的数据都是疯狂的)。
在大型表格上,年月日查询将非常缓慢。 有些数据库让你在函数结果上添加索引,但是ActiveRecord太愚蠢,无法理解它们,所以如果你尝试使用它们,它会变得很糟糕; 所以,如果您发现这些查询太慢,那么您将不得不添加您试图避免的三个额外的列。
如果你打算使用这些查询很多,那么你可以为它们添加范围,但是推荐的方法是用一个参数添加范围只是添加一个类方法:
使用类方法是接受范围参数的首选方法。 这些方法仍然可以在关联对象上访问…
所以你应该有这样的类方法:
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
试试这个
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的开始date和结束date之间的所有模型。
我喜欢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)
这将是另一个:
def self.by_year(year) where("published_at >= ? and published_at <= ?", "#{year}-01-01", "#{year}-12-31") end
在SQLite中对我来说工作得很好。
尝试这个:
Model.where("MONTH(date_column) = ? and DAY(date_column) = ?", DateTime.now.month, DateTime.now.day)
简单的实施只是一年
应用程序/模型/ your_model.rb
scope :created_in, ->(year) { where( "YEAR( created_at ) = ?", year ) }
用法
Model.created_in(1984)
不需要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)