【问题标题】:How do you combine multiple Rails SQL queries into a single query in rails?如何在 Rails 中将多个 Rails SQL 查询组合成一个查询?
【发布时间】:2014-01-10 04:35:18
【问题描述】:

在我的 rails 代码中,我需要根据记录日期和记录收到的投票的组合对表运行查询。我在 rails 中像下面这样完成它:

if params[:sort_by] == "default"
    objs1 = class_name.where("created_at between '#{Date.today - 7}' and '#{Date.today}' and net_votes > 0").order("net_votes DESC")
    objs2 = class_name.where("created_at between '#{Date.today - 30}' and '#{Date.today - 7}' and net_votes > 0").order("net_votes DESC")
    objs3 = class_name.where("created_at between '#{Date.today - 90}' and '#{Date.today - 30}' and net_votes > 0").order("net_votes DESC")
    objs4 = class_name.where("created_at < '#{Date.today - 90}' and net_votes > 0").order("net_votes DESC")
    objs = objs1 + objs2 + objs3 + objs4

抛开效率不谈,我不能在组合查询结果上使用分页,更不用说代码非常难看。这样做的正确方法是什么?

提前致谢。

【问题讨论】:

    标签: mysql sql ruby-on-rails postgresql rails-activerecord


    【解决方案1】:

    使用order 进行排序逻辑,而不是where

    order_by_sql = <<-SQL
    CASE WHEN created_at between '#{Date.today - 7}' and '#{Date.today}' THEN 1
         WHEN created_at between '#{Date.today - 30}' and '#{Date.today - 7}' THEN 2
         WHEN created_at between '#{Date.today - 90}' and '#{Date.today - 30}' THEN 3
         ELSE 4
    END
    SQL
    
    objs = class_name.where('net_votes > 0').order(order_by_sql)
    

    【讨论】:

    • 太棒了,这为查询带来了 50% 的性能提升。谢谢
    【解决方案2】:

    您可以做一些事情来使它更优雅并表现更好:

    1) 将每个条件封装到一个作用域中。例如,net_vtoes > 0 是可重用的:

    def self.has_votes
      where("net_votes > 0")
    end
    
    def self.ordered 
      order("net_votes DESC")
    end
    
    def self.last_week
      where("created_at between '#{Date.today - 7}' and '#{Date.today}'")
    end
    

    2) 按照 Ryan Bates 在此 RailsCast 中的建议创建一个范围运算符,以允许您以 OR 方式组合 where 条件:http://railscasts.com/episodes/355-hacking-with-arel?view=asciicast。这将让你构建一个这样的语句:

    (MyClass.last_week | MyClass.last_month).has_votes.ordered
    

    【讨论】:

    • 由于在构建查询之前您不会实例化模型,因此不会产生所需的排序顺序...
    • 为什么? ordered 是一个活动记录范围,| 是一个新的运算符,它将范围与 SQL OR 语句相结合。也许你把它和标准的数组联合运算符混淆了?
    • 是的,但有序范围不会强制按照需要进行相同的排序。 OP 的代码导致在过去一周创建的记录,然后是过去一个月,然后是 90 天,然后是其他所有记录。您的范围仅根据投票数对它们进行排序(不确定您从哪里获得的)。
    猜你喜欢
    • 2017-09-02
    • 2018-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多