针对Heroku的Rails数据库特定查询

时间:2011-04-05 19:01:00

标签: mysql ruby-on-rails database postgresql heroku

我最近一直在向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

提前感谢任何人的任何输入。

3 个答案:

答案 0 :(得分:4)

您应该使用标准EXTRACT功能:

named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (extract(year from created_at) = ?)", true, (args.first)], :order => "created_at DESC"} }

PostgresSQLMySQL都支持它。

答案 1 :(得分:2)

不幸的是,这种情况很多,但是你有一般的正确想法。

你的第一种攻击方法是查看MySQL和Postres中是否存在一个函数,但在这种情况下这是不可能的。

我要提出的一个建议是,此解决方案中存在大量代码重复。考虑到条件语句是这里唯一的兼容问题,我会考虑仅对条件进行兼容性检查:

示例(Semi-Psuedo Code):

named_scope :by_year, lambda { |*args| {:conditions => ["published = ? AND (#{by_year_condition} = ?)", true, (args.first)], :order => "created_at DESC"} }


#...code...

def by_year_condition
  if postgres
     "date_part('year', created_at)"
  else
     "YEAR(created_at)"
end

答案 2 :(得分:1)

另一种选择是为每个日期部分(daymonthyear)创建计算列,并直接查询这些列。您可以使用模型代码或触发器使它们保持最新。您还可以在yearmonthday列上为各种组合编制索引。在where子句中使用函数时,数据库在正确使用索引方面是非常糟糕的,特别是当该函数从列的中间抽出一部分数据时。

拥有三个单独列的好处是您的查询将不再依赖任何供应商的SQL实现。