2014-09-05 2 views
3

У меня есть сфера определяется следующим образом:Запись «не в» SQL-запрос с использованием AREL

scope :ignore_unavailable, lambda { 
    where([ "Item.id NOT IN (SELECT id FROM Cars WHERE Cars.status = 'NA'" ]) 
} 

В настоящее время ее использование жестко закодированные таблицы имен. Как я могу улучшить его с помощью таких фреймворков, как Arel? Поймите любую помощь здесь.

Я на Rails 3.2

ответ

4

Если вы используете рельсы 4, один из способов будет

scope :ignore_unavailable, lambda { 
    where.not(id: Car.where(:status => "NA").pluck(:id)) 
} 

Для рельсов 3

scope :ignore_unavailable, lambda { 
    where("id not in (?)", Car.where(:status => "NA").pluck(:id)) 
} 
+0

К сожалению, я на рельсах 3.2 –

+0

Обновлен мой ответ для рельсов 3 – usha

+1

Спасибо. Отлично! Один вопрос, хотя, не будем ли мы выполнять два SQL-запроса здесь вместо одного, как в оригинальном случае? –

5

Поскольку описание задачи требует ответа, используя AREL, я представляю следующие:

class Car 
    scope :available, -> { where(arel_table[:status].not_in(['NA'])) } 
end 

class Item 
    scope :available, -> { where(:id => Car.available) } 
end 

СКП должно быть что-то вроде следующего:

SELECT [items].* 
FROM [items] 
WHERE [item].[id] IN (
    SELECT [cars].[id] 
    FROM [cars] 
    WHERE [car].[status] NOT IN ('NA') 
) 

Очевидно, что рельсы 4 имеет not сферу, так что это решение для рельсов 3.

Приведенный выше код имеет два преимущества:

  • Он выполняет один запрос
  • в столбцах таблицы правильно пространства имен (в отличии при использовании сырого SQL)
+0

Спасибо большое! У меня были проблемы с пространствами имен в сложном запросе, только Арель мог помочь мне здесь. :) –