Ruby on rails 如何使用Arel将表列引用为子句条件?
我有这个范围:Ruby on rails 如何使用Arel将表列引用为子句条件?,ruby-on-rails,activerecord,arel,Ruby On Rails,Activerecord,Arel,我有这个范围: 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
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语法。
但我不知道如何在方法中使用表列引用。我尝试过此方法,但出现异常:
> 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语句相关的条件有四个:
开始时间在开始时间和结束时间的范围内
在开始时间和结束时间范围内完成
开始时间在开始时间和结束时间范围内
开始时间和结束时间范围内的结束时间
基本上,这只是一个日期范围重叠
我把它改写成
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)
}
也许有一种更简单的方法来实现我的目标?据我所知,您希望选择所有记录,哪个范围与指定的记录相交?如果是这样,只需选择记录,这些记录的起始值在范围结束之前,而结束值在范围开始之后。因此,它应该是:
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
请看一下我的更新问题-我已经为这个查询添加了可能的解决方案和条件。也许你可以复习一下?谢谢@蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆尔哈菲佐夫,蒂姆,蒂姆尔哈菲佐夫,蒂姆,蒂姆,蒂姆尔哈菲佐夫,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆尔哈菲佐夫,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆尔哈菲佐夫,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂姆,蒂。非常感谢。