我有一个具有日期属性的ActiveRecord模型。是否可以利用该date属性按年,日和月查找:
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
还是有可能find_by_date(2012-12-1)。
我希望可以避免创建Year,Month和Day属性。
我有一个具有日期属性的ActiveRecord模型。是否可以利用该date属性按年,日和月查找:
Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)
还是有可能find_by_date(2012-12-1)。
我希望可以避免创建Year,Month和Day属性。
Answers:
假设您的“日期属性”是日期(而不是完整的时间戳记),那么简单的方法where
将为您提供“按日期查找”:
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
格式说明会在某些情况下,添加前导零,并能迷惑平等的测试,因此cast(... as int)
迫使格式化字符串的数字。
ActiveRecord不会保护您免受数据库之间的所有差异的影响,因此,一旦您做任何不重要的事情,您要么必须构建自己的可移植层(难看但有时是必要的),将自己绑定到有限的一组数据库中(现实除非您发布的内容必须在任何数据库上运行),或者在Ruby中执行所有逻辑(对于任何非平凡的数据量来说都是疯狂的)。
在大型表上,年,月和月中的查询将非常慢。有些数据库允许您在函数结果上添加索引,但是ActiveRecord太愚蠢而无法理解它们,因此,如果尝试使用它们,将会造成很大的麻烦。因此,如果您发现这些查询太慢,则必须添加要避免的三个额外的列。
如果您将大量使用这些查询,则可以为其添加作用域,但是建议使用参数添加作用域的方法只是添加一个类方法:
使用类方法是接受范围参数的首选方法。这些方法仍然可以在关联对象上访问...
因此,您将拥有如下所示的类方法:
def self.by_year(year)
where('extract(year from date_column) = ?', year)
end
# etc.
CAST
将日期数字设置为整数而不是加0(由于某种原因,加0会给我错误的数字)。然后,我修改过的过滤器是: 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)
cast(... as int)
总比骗术好,我不确定为什么我一开始就没有使用cast
。
TO_CHAR
与ILIKE
在只有一条线,我贴了完整的例子,在这个线程结束
对于MySQL,请尝试一下
Model.where("MONTH(date_column) = 12")
Model.where("YEAR(date_column) = 2012")
Model.where("DAY(date_column) = 24")
我认为最简单的方法是在范围内:
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。
'd >= ? and d < ?', dt.beginning_of_day, dt.tomorrow.beginning_of_day
。使用<
和>
错过天之间的界限。
app/models/your_model.rb
scope :created_in, ->( year ) { where( "YEAR( created_at ) = ?", year ) }
用法
Model.created_in( 1984 )
尝试这个:
Model.where("MONTH(date_column) = ? and DAY(date_column) = ?", DateTime.now.month, DateTime.now.day)
MONTH
功能。尝试提取或date_part。wiki.postgresql.org/wiki/MONTH()_equivalent postgresqltutorial.com/postgresql-date_part
不需要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)
我通常使用:
Model.where('extract(month from birthday_column) = ? and extract(day from birthday_column) = ?', Time.now.month, Time.now.day)
如果您只是在寻找日期,只需执行以下操作:
Model.where(date: Date.today.beginning_of_day..Date.today.end_of_day)