Rails union hack, как собрать два разных запроса вместе

У меня есть запрос, который ищет два отдельных поля в одной таблице... ищет места, которые скорее всего являются конкретным городом, но также может быть страной... т.е. необходимостью для двух полей.

Таблица выглядит так:

Country    City

Germany    Aachen
USA        Amarillo
USA        Austin

Результат:

Keyword   Sideinfo

Aachen    Germany
USA       Country
Austin    USA
Germany   Country 

В основном мне интересно, есть ли более сжатый способ сделать это, потому что мне пришлось использовать два отдельных запроса, затем добавить их вместе, отсортировать их и т.д. (что отлично работает):

  def self.ajax(search)
    countries = Location.find(:all, :select=> 'country AS keyword,  "Country" AS sideinfo', :joins => :hotels, :conditions => [ 'hotels.email IS NOT NULL AND country LIKE ?', "#{search}%" ], :group => :country )
    cities = Location.find(:all, :select=> 'city AS keyword, country AS sideinfo', :joins => :hotels, :conditions => [ 'hotels.email IS NOT NULL AND city LIKE ?', "#{search}%" ], :group => :city )
    out = cities + countries
    out = out.sort { |a,b| a.keyword <=> b.keyword }
    out.first(8)
  end

Я не мог найти информацию о том, как использовать соединения с помощью ActiveRecord...

Ответы

Ответ 1

Выполнение запроса UNION изначально невозможно с помощью ActiveRecord. Итак, есть два решения:

  • Используя find_by_sql, создайте свой запрос так, как хотите. Я бы не советовал об этом.
  • Используя плагин, например union, выполните запрос sql-соединения UNION.

Ответ 2

Я нашел аккуратный взломать с помощью select. Например, если вы хотите создать соединение между User и OtherUser.

User.select('id from other_users union select id')

это сгенерирует этот SQL

"SELECT id from other_users union select id FROM users " 

Если у вас есть области с условиями, вы можете использовать метод ActiveRecord:: Relation where_values ​​

condition = OtherUser.example_condtion_scope.where_values.join(' ')
User.select("id from other_users where #{contition}")

Ответ 3

Используя плагин union, он теперь прекрасно работает благодаря:

  def self.ajax3(search)
    Location.union( [{ :select => 'city AS keyword, country AS sideinfo', 
                       :joins => :hotels, 
                       :conditions => [ 'email IS NOT NULL AND city LIKE ?', "#{search}%" ]}, 
                     { :select => 'country AS keyword, "Country" AS sideinfo', 
                       :joins => :hotels, 
                       :conditions => [ 'email IS NOT NULL AND country LIKE ?', "#{search}%" ]}] )
  end

Ответ 4

Теперь это возможно в Rails 4,

locations = Location.arel_table
hotels = Hotel.arel_table

countries = Location
                .select(locations[:country].as("keyword"))
                .joins(:hotels)
                .where(hotels[:email].not_eq(nil))
                .where(locations[:country].matches("#{search}%"))

cities = Location
            .select(locations[:city].as("keyword"))
            .joins(:hotels)
            .where(hotels[:email].not_eq(nil))
            .where(locations[:city].matches("#{search}%"))

union = countries.union(cities)

result = Location.from(locations.create_table_alias(union, :locations).to_sql)