2014-12-12 2 views
0

У меня есть этот объем:Как передать столбец таблицы как условие условия с 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_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 утверждением:

  1. start_at в диапазоне begin_time и end_time
  2. finish_at в диапазоне begin_time и end_time
  3. begin_time я п диапазон start_time и finish_time
  4. 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

Ну, насколько я понял, вы хотите выбрать всю запись, в каком диапазоне есть пересечение с указанным? Если это так, просто выберите записи, которые имеют значения полей start_at, которые находятся до конца диапазона, и имеют значения полей finish_at, которые находятся после начала диапазона. Таким образом, с это должно быть:

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 
+0

Пожалуйста, взгляните на мой вопрос с обновлением - я добавил возможные варианты и условия для этого запроса. Может быть, вы можете просмотреть его? Благодаря! –

+0

@TimurKhafizov на самом деле ваш вариант правильный, но моего достаточно, и он проще, я когда то вычислял как правильно и оптимально считать пересечения диапазонов. –

+0

Да, все мои тесты проходят, поэтому это лучшее решение. Спасибо! –

Смежные вопросы