【问题标题】:ARel: Add additional conditions to an outer joinARel:向外部联接添加附加条件
【发布时间】:2012-01-25 16:24:49
【问题描述】:

我的 Rails 应用程序中有以下模型:

class Shift < ActiveRecord::Base
  has_many :schedules
  scope :active, where(:active => true)
end

class Schedule < ActiveRecord::Base
  belongs_to :shift
end

我希望生成所有活动班次的集合,并急切地加载在两个给定日期之间具有occurs_on 的任何关联时间表。如果班次在这些日期之间没有时间表,则仍应在结果中返回。

本质上,我想生成的 SQL 相当于:

SELECT shifts.*, schedules.*
FROM shifts
  LEFT JOIN schedules ON schedules.shift_id = shifts.id
    AND schedules.occurs_on BETWEEN '01/01/2012' AND '01/31/2012'
WHERE shifts.active = 't';

我的第一次尝试是:

Shift.active.includes(:schedules).where("schedules.occurs_on BETWEEN '01/01/2012' AND '01/31/2012')

问题是发生在 where 子句中的过滤,而不是在连接中。如果班次在该期间没有时间表,则根本不会返回。

我的第二次尝试是使用joins 方法,但这是一个内部连接。同样,这将删除该期间没有时间表的所有班次。

我很沮丧,因为我知道我希望 AREL 生成的 SQL,但我不知道如何用 API 来表达它。有人吗?

【问题讨论】:

    标签: ruby-on-rails activerecord ruby-on-rails-3.1 arel


    【解决方案1】:

    您可以尝试一些非常原始的 AREL。免责声明:我没有实际的 ScheduleShift 类,所以我无法正确测试它,但我使用了一些现有的表在我自己的机器上对其进行了故障排除。

    on = Arel::Nodes::On.new(
      Arel::Nodes::Equality.new(Schedule.arel_table[:shift_id], Shift.arel_table[:id]).\
      and(Arel::Nodes::Between.new(
        Schedule.arel_table[:occurs_on],
        Arel::Nodes::And.new(2.days.ago, Time.now)
      ))
    )
    join = Arel::Nodes::OuterJoin.new(Schedule.arel_table, on)
    Shift.joins(join).where(active: true).to_sql
    

    【讨论】:

      【解决方案2】:

      您可以使用 SQL 片段作为 joins 方法调用的参数:

      Shift.active.joins('LEFT OUTER JOIN schedules ON schedules.occurs_on...')
      

      【讨论】:

        【解决方案3】:

        您可以使用 Arel 构建原始 sql 查询,如下所示:

        @start_date
        @end_date
        
        @shift = Shift.arel_table
        @schedule = Schedule.arel_table
        
        @shift.join(@schedule)
                .on(@schedule[:shift_id].eq(@shift[:id])
                      .and(@schedule[:occurs_on].between(@start_date..@end_date)))
              .to_sql
        

        【讨论】:

          猜你喜欢
          • 2012-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-27
          • 1970-01-01
          • 2018-08-02
          • 2010-11-13
          相关资源
          最近更新 更多