【问题标题】:Rails database specific queries for Heroku针对 Heroku 的 Rails 数据库特定查询
【发布时间】:2011-04-05 19:00:59
【问题描述】:

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

提前感谢任何人的任何意见。

【问题讨论】:

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


    【解决方案1】:

    您应该使用标准的EXTRACT 函数:

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

    PostgresSQLMySQL 都支持它。

    【讨论】:

      【解决方案2】:

      不幸的是,这种情况经常发生,但是你有一个正确的想法。

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

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

      示例(半伪代码):

      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
      

      【讨论】:

      • 是的,代码重复是我真正提出问题的原因,这是我想尝试但不做的事情。您的建议肯定是一个很好的建议,谢谢。
      【解决方案3】:

      另一种选择是为每个日期部分(daymonthyear)创建计算列并直接查询这些列。您可以使用您的模型代码或触发器使它们保持最新。您还将受益于能够对yearmonthday 列上的各种组合进行索引。当您在 where 子句中使用函数时,数据库在正确使用索引方面是出了名的糟糕,尤其是当该函数从列的中间提取一部分数据时。

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-01-19
        • 1970-01-01
        • 2012-11-18
        • 1970-01-01
        • 2014-01-01
        • 2012-08-06
        • 1970-01-01
        相关资源
        最近更新 更多