Heroku 的 Rails 数据库特定查询
我最近一直在 Heroku 上部署一些应用程序。我在本地开发机器上运行 MySQL,并花了一些时间更新一些范围以在 PostgreSQL 中工作。然而,我收到的一个错误被证明很难改变。
目前我的模型中有一个数据库特定的案例语句。我理解为什么会发生有关 MySQL 日期函数的错误,但我不确定这是否是最有效的解决方案。有谁有更好的方法来实现适用于 MySQL 和 PostgreSQL 的修复程序?
case ActiveRecord::Base.connection.adapter_name
when 'PostgreSQL'
named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (date_part('year', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_month, lambda { |*args| {:conditions => ["published = ? AND (date_part('month', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_day, lambda { |*args| {:conditions => ["published = ? AND (date_part('day', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
else
named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (YEAR(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_month, lambda { |*args| {:conditions => ["published = ? AND (MONTH(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_day, lambda { |*args| {:conditions => ["published = ? AND (DAY(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
end
仅供参考,这是我收到的 PostgreSQL 错误:
PGError: ERROR: function month(timestamp without time zone) does not exist LINE 1: ...T * FROM "articles" WHERE (((published = 't' AND (MONTH(crea... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. : SELECT * FROM "articles" WHERE (((published = 't' AND (MONTH(created_at) = '11')) AND (published = 't' AND (YEAR(created_at) = '2010'))) AND ("articles"."published" = 't')) ORDER BY created_at DESC LIMIT 5 OFFSET 0
提前感谢任何人提供的任何信息。
I've been deploying some apps to Heroku recently. I run MySQL on my local dev machine and have spent a little while updating some of my scopes to work in PostgreSQL. However one i have received an error on is proving difficult to change.
For the time being i've got a database specific case statement in my model. I understand why the error regarding the MySQL date functions is occurring, but im not sure if this is the most efficient solution. Does anyone have a better way of implementing a fix that will work with both MySQL and PostgreSQL?
case ActiveRecord::Base.connection.adapter_name
when 'PostgreSQL'
named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (date_part('year', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_month, lambda { |*args| {:conditions => ["published = ? AND (date_part('month', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_day, lambda { |*args| {:conditions => ["published = ? AND (date_part('day', created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
else
named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (YEAR(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_month, lambda { |*args| {:conditions => ["published = ? AND (MONTH(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
named_scope :by_day, lambda { |*args| {:conditions => ["published = ? AND (DAY(created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }
end
FYI, this is the PostgreSQL error that i am getting:
PGError: ERROR: function month(timestamp without time zone) does not exist LINE 1: ...T * FROM "articles" WHERE (((published = 't' AND (MONTH(crea... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts. : SELECT * FROM "articles" WHERE (((published = 't' AND (MONTH(created_at) = '11')) AND (published = 't' AND (YEAR(created_at) = '2010'))) AND ("articles"."published" = 't')) ORDER BY created_at DESC LIMIT 5 OFFSET 0
Thanks in advance for any input anyone has.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您应该使用标准
EXTRACT
函数:两者 PostgresSQL 和 MySQL 支持它。
You should be using the standard
EXTRACT
function:Both PostgresSQL and MySQL support it.
不幸的是,这种情况经常发生,但你的想法总体是正确的。
第一种攻击方法是查看 MySQL 和 Postres 中是否存在同时存在的函数,但在本例中这是不可能的。
我要提出的一个建议是,这个解决方案中有很多代码重复。考虑到条件语句是这里唯一的兼容问题,我将仅针对条件排除兼容性检查:
示例(半伪代码):
Unfortunately this happens alot, however you have the general right idea.
Your first method of attack is to see if there is a function that exists both in MySQL and Postres, however this isn't possible in this case.
The one suggestion I would make is that there is a lot of code duplication in this solution. Considering the condition statement is the only compatible issue here, I would factor out the compatiablity check only for the condition:
Example (Semi-Psuedo Code):
另一种选择是为每个日期部分(
日
、月
和年
)创建计算列,并直接针对这些部分进行查询。您可以让他们使用您的模型代码或触发器保持最新状态。您还可以受益于能够对年
、月
和日
列上的各种组合建立索引。当您在 where 子句中使用函数时,尤其是当该函数从列中间提取部分数据时,数据库在正确使用索引方面是出了名的糟糕。拥有三个独立列的好处是您的查询将不再依赖于任何供应商的 SQL 实现。
Another option would be to create computed columns for each of your date parts (
day
,month
, andyear
) and to query directly against those. You could keep them up to date with your model code or with triggers. You'll also get the benefit of being able to index on various combinations on youryear
,month
, andday
columns. Databases are notoriously bad at correctly using indexes when you use a function in the where clause, especially when that function is pulling out a portion of data from the middle of the column.The upside of having three separate columns is that your query will no longer rely on any vendor's implementations of SQL.