2010-08-03 4 views
0

J'essaye de faire une recherche qui commande les résultats par leur nom de famille et ensuite par le nom de famille du client.Rails complexes trouver la commande

Customer.find(:all, 
    :conditions =>['customers.id IN (?)', intersection], 
    :joins => 'JOIN histories ON histories.customer_id = customers.id 
    JOIN houses ON histories.house_id = houses.id', 
    :order => "houses.name ASC, customers.last_name ASC", 
    :select => "customers.*, histories.job_title, houses.name" 
) 

Mon problème est que cela retournera tous les historiques liés à chaque client. Si j'ajoute AND histories.finish_date IS NULL Cela empêchera le retour de tous les historiques du client sélectionné, mais empêchera également les clients de l'intersection qui n'ont pas d'historique ou un jeu finish_date d'être renvoyés. Fondamentalement, j'ai besoin de chaque client dans l'intersection retourné une fois avec le nom de la maison actuelle (s'ils en ont un) et ensuite triés par nom de leur maison et ensuite leur nom de famille.

Alors, y a-t-il une façon de procéder?

Voici un exemple

client

id last_name 
1  franks 
2  doors 
3  greens 

histoires

id finish_date  house_id  customer_id 
1  NULL    1    1 
2  NULL    2    2 
3  11/03/10   2    1 
4  22/04/09   1    2 

NULL = maison actuelle

maisons

id name 
1 a 
2 b 

Résultats

intersection = 1,2,3

last_name  house  
franks   a 
doors    b 
greens   NULL 

Merci

Répondre

0

Je pense que vous devez utiliser des jointures externes.

Par exemple, cela devrait fonctionner:

Customer.find(:all, 
    :conditions =>['customers.id IN (?) and histories.finish_date is null', intersection], 
    :joins => 'LEFT OUTER JOIN histories ON histories.customer_id = customers.id 
    LEFT OUTER JOIN houses ON histories.house_id = houses.id', 
    :order => "houses.name ASC, customers.last_name ASC", 
    :select => "customers.*, histories.job_title, houses.name" 
) 

Si vous avez une association entre le Client et l'histoire et entre l'histoire et de la Chambre, vous devriez être en mesure de faire :include => [:histories => :house] au lieu de l'option :joins. La seule autre chose est que les clients sans maison apparaîtront en premier dans la liste parce que NULL est plus tôt dans la commande qu'une valeur non NULL. Vous pouvez essayer une option de commande comme ceci:

:order => 'isnull(houses.name), houses.name, customers.last_name' 

pour obtenir ce que vous avez spécifié.

+0

La requête renvoie uniquement les personnes avec des historiques pas les personnes sans. Y a-t-il une jointure qui retournera toujours le client même s'il n'a pas d'histoire? – Josh

+0

Curieux. Cela a fonctionné pour moi localement. La jointure externe doit renvoyer les clients même s'ils n'ont pas d'historique. Pouvez-vous regarder vos journaux et voir quelle requête SQL a été générée à partir de cette recherche? – Shadwell

+0

MERCI! Juste changé la requête à utiliser: inclure et maintenant cela fonctionne – Josh

0

OMI il est plus simple de faire la logique de tri dans Rails au lieu de la base de données :

customers = Customer.find(:all, :conditions => { :id => intersection }, :include => [ { :histories => :houses } ]) 

customers.sort_by { |c| c.last_name } 
customers.sort_by do |c| 
    current_house = c.histories.find_by_finish_date(nil) # Returns nil if no matching record found 
    if current_house 
    current_house.name 
    else 
    '' 
    end 
end 

Explications

  • : les conditions peuvent prendre un hachage {: column_name => array} qui se traduit par votre IN où condition
  • : comprennent pré-charge (eager loading) les tables si le correspondant les associations existent. Pour le dire autrement:: jointures crée INNER JOINs, tandis que: include crée LEFT JOINs. Ici, nous allons laisser des histoires de jointure et encore des maisons de gauche. Vous pouvez omettre ceci: tag d'inclusion, auquel cas rails fait une nouvelle requête chaque fois que vous accédez à une propriété history ou houses. Sort_by permet de définir un critère de tri personnalisé. Find_by_finish_date est l'une des méthodes magiques des rails; il est équivalent à h.find(:conditions => {:finish_date => nil })
  • Comment sortir: Il suffit de les afficher tous dans votre vue. S'il n'a pas d'historique, customer.histories est un tableau vide.
+0

merci pour votre réponse. J'ai ajouté un exemple à ma question. Le problème im ayant est heureusement plus clair :) – Josh

+0

Est-ce que ça va comme ça? – giraff

+0

Je comprends ce que vous voulez dire, mais le problème est de savoir comment vous obtenez la trouvaille pour retourner les détails des clients, même s'ils n'ont pas d'histoire? – Josh

Questions connexes