2009-10-18 11 views
13

J'ai une requête qui recherche deux champs distincts dans le même tableau ... à la recherche d'emplacements qui sont probablement une ville spécifique, mais qui pourraient également être un pays ... c'est-à-dire le besoin de deux champs.rails union hack, comment regrouper deux requêtes différentes

Table ressemble:

Country City 

Germany Aachen 
USA  Amarillo 
USA  Austin 

Résultat:

Keyword Sideinfo 

Aachen Germany 
USA  Country 
Austin USA 
Germany Country 

En fait, je me demande s'il y a une façon de faire plus concis parce que je devais utiliser deux requêtes distinctes puis les ajouter ensemble, les trier, etc (qui fonctionne bien):

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 

Je n'ai trouvé aucune information sur la façon de unions utilisant ActiveRecord ...

+1

Cette question dis cusses façons d'utiliser ou de fausses unions dans ActiveRecord: http://stackoverflow.com/questions/6686920/activerecord-query-union –

Répondre

7

L'exécution d'une requête UNION n'est pas possible en mode natif avec ActiveRecord. Il y a donc deux solutions:

  • En utilisant find_by_sql pour construire votre requête comme vous le souhaitez. Je ne conseillerais pas pour cela.
  • L'utilisation d'un plug-in comme union pour faire une requête SQL UNION.
+4

Union a 3 ans maintenant. Quelqu'un a eu une solution plus à jour –

+0

@BillLeeper bien que votre commentaire a été posté en '12, vérifiez ma réponse au cas où vous êtes toujours à la recherche –

+0

@BillLeeper https://github.com/brianhempel/active_record_union est un meilleur petit bijou. Utilisez les unions sur les étendues ActiveRecord sans laideur. – lingceng

2

Utilisation du plugin union, il fonctionne maintenant magnifiquement grâce:

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 
3

J'ai trouvé un hack propre à l'aide de sélection. Par exemple si vous voulez faire une union entre Utilisateur et AutreUtilisateur.

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

cela va générer ce SQL

"SELECT id from other_users union select id FROM users " 

Si vous avez des champs avec les conditions que vous pouvez utiliser le ActiveRecord :: Relation where_values ​​méthode

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

Ceci est maintenant possible 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)