我有这个范围:
scope :in_range, lambda { |begin_time, end_time, excluded_sales = nil|
where(
'start_at BETWEEN ? AND ? OR finish_at BETWEEN ? AND ? OR ? BETWEEN start_at AND finish_at OR ? BETWEEN start_at AND finish_at',
begin_time, end_time, begin_time, end_time, begin_time, end_time)
.where.not(id: excluded_sales)
}
这会产生
> Sale.in_range(Time.now, Time.now + 1)
Sale Load (0.6ms) SELECT "sales".* FROM "sales" WHERE (start_at BETWEEN '2014-12-12 10:45:47.065712' AND '2014-12-12 10:45:48.065714' OR finish_at BETWEEN '2014-12-12 10:45:47.065712' AND '2014-12-12 10:45:48.065714' OR '2014-12-12 10:45:47.065712' BETWEEN start_at AND finish_at OR '2014-12-12 10:45:48.065714' BETWEEN start_at AND finish_at) AND ("sales"."id" IS NOT NULL)
我需要使用Arel重写这个范围,因为我相信我不应该在这里使用原始SQL语法。
但我不知道如何使用in
方法与表列引用。我尝试了这个但却异常:
> s = Sale.arel_table
> begin_time = Time.now
> Sale.where(begin_time.in(s[:start_at]..s[:finish_at]))
--> ArgumentError: bad value for range
也尝试了这个,但没有运气:
> s = Sale.arel_table
> begin_time = Time.now
> Sale.where(begin_time.in('sales.start_time'..'sales.end_time')
--> NoMethodError: undefined method `round' for "sales.end_time".."sales.start_time":Range
请告知如何使用Arel引用表列作为子句条件?
谢谢!
更新:
OR
语句有四个条件:
start_at
,范围为begin_time
和end_time
finish_at
,范围为begin_time
和end_time
begin_time
,范围为start_time
和finish_time
end_time
,范围为start_time
和finish_time
基本上它只是一个日期范围重叠。
我把它改写成
scope :in_range, lambda { |date_range, excluded_sales = nil|
s = Sale.arel_table
where(
s.grouping(s[:starts_at].gteq(date_range.first).and(s[:starts_at].lteq(date_range.last)))
.or(s.grouping(s[:ends_at].gteq(date_range.first).and(s[:ends_at].lteq(date_range.last))))
.or(s.grouping(s[:starts_at].lteq(date_range.first).and(s[:ends_at].gteq(date_range.last))))
.or(s.grouping(s[:starts_at].gteq(date_range.first).and(s[:ends_at].lteq(date_range.last))))
).where.not(id: excluded_sales)
}
也许有一种更简单的方法来实现我的目标?
答案 0 :(得分:0)
据我所知,您希望选择所有记录,哪个范围与指定范围有交集?如果是这样,只需选择记录,其中start_at
字段值在范围结束之前,并且具有在范围开始之后的finish_at
字段值。因此arel应该是:
scope :in_range, proc do |begin_time, end_time, excluded_sales|
where(arel_table[:start_at].lteq(end_time)
.and(arel_table[:finish_at].gteq(begin_time))
.and(arel_table[:id].not_eq(excluded_sales)))
end