如果您的effective_end_date
和effective_start_date
列确实是日期,那么您的查询毫无意义,因为日期的最小分辨率为一天,而 900 比 86400(AKA25*60*60
或 1 天)小很多。因此,我假设您的“日期”列实际上是日期时间(AKA 时间戳)列;如果这是真的,那么您可能想要重命名列以避免在维护期间出现混淆,effectively_starts_at
并且effectively_ends_at
可能与通常的 Rails 约定很好匹配。如果此假设无效,那么您应该更改列类型或停止使用 900。
回到真正的问题。ActiveRecord 使用以下方法将 Ruby 值转换为 SQL 值ActiveRecord::ConnectionAdapters::Quoting#quote
:
def quote(value, column = nil)
# records are quoted as their primary key
return value.quoted_id if value.respond_to?(:quoted_id)
case value
#...
else
"'#{quote_string(YAML.dump(value))}'"
end
end
因此,如果您尝试使用某个值作为占位符的值,并且没有为该类型内置任何特定处理,那么您会得到 YAML(默认值 IMO 的一个奇怪选择)。此外,900.seconds
是一个ActiveSupport::Duration
对象(尽管900.seconds.class
说了些什么)并且case value
没有分支,ActiveSupport::Duration
因此900.seconds
将获得 YAML 化。
PostgreSQL 适配器提供了自己的quote
输入,ActiveRecord::ConnectionAdapters::PostgreSQLAdapter#quote
但也不知道ActiveSupport::Duration
。MySQL 适配器quote
也不知道ActiveSupport::Duration
. quote
您可以在这些方法中添加一些意义。在初始化程序中是这样的:
class ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
# Grab an alias for the standard quote method
alias :std_quote :quote
# Bludgeon some sense into things
def quote(value, column = nil)
return "interval '#{value.to_i} seconds'" if(value.is_a?(ActiveSupport::Duration))
std_quote(value, column)
end
end
有了那个补丁,当你使用 PostgreSQL 时,你会得到 PostgreSQL 理解的间隔ActiveSupport::Duration
:
> Model.where('a - b > ?', 900.seconds).to_sql
=> "SELECT \"models\".* FROM \"models\" WHERE (a - b > interval '900 seconds')"
> Model.where('a - b > ?', 11.days).to_sql
=> "SELECT \"models\".* FROM \"models\" WHERE (a - b > interval '950400 seconds')"
如果您向 MySQL 适配器添加一个类似的补丁quote
(留给读者作为练习),则如下所示:
UserRole.where("(effective_end_date - effective_start_date) > ?", 900.seconds)
将在 PostgreSQL 和 MySQL 中做正确的事情,您的代码不必担心它。
也就是说,在不同的数据库上开发和部署是一个非常糟糕的主意,这会让圣诞老人哭泣并为你的长袜寻找一些煤炭(可能含有砷,可能是放射性的)。所以不要那样做。
另一方面,如果您正在尝试构建与数据库无关的软件,那么您将度过一段快乐的时光!数据库可移植性在很大程度上是一个神话,与数据库无关的软件总是意味着在您的平台提供的 ORM 和数据库接口之上编写您自己的可移植层。您将不得不在您计划支持的每个数据库上详尽地测试所有内容,每个人都对 SQL 标准进行口头服务,但似乎没有人完全支持它,每个人都有自己的扩展和怪癖需要担心。您最终将编写自己的可移植层,其中包含实用方法和猴子补丁的混合。