2013-01-07 5 views
11

Ich habe ein Clientmodell und ein Produktmodell, in dem ein Client viele Produkte hat und ein Produkt zu einem CLient gehört.Rails ActiveRecord gibt Records zurück, wo ID in verwandter Tabelle existiert

Ich brauche eine Abfrage zu finden, die nur Clients zurückgibt, wenn sie

id |  name 
-------------- 
1 | Company A 
2 | Company B 
3 | Company C 

Produkte Tisch

id |  name | client_id 
--------------------------- 
1 | Product A |   1 
2 | Product B |   1 
3 | Product C |   3 
4 | Product D |   3 
5 | Product E |   1 

ich einen Datensatz in der Product-Tabelle

Kunden Tabelle nur haben müssen Clients 1 3

Zum Beispiel so etwas wie

@clients = Client.where("client exists in products") #something to this effect 
+0

tut '@clients = Client.joins (: products) 'funktioniert? Ich denke, es wird ein INNER JOIN tun, das ist (glaube ich), was Sie – pjam

+0

mögen, dass eine gute Frage ist, werde ich in der Konsole testen – ctilley79

+0

@pjam Es scheint, zu den Kunden verbunden alle Produkte zurück, also ist am Ende mit doppelte Kundennamen. Gibt es eine Möglichkeit, die Ergebnisse auf die Clients zu beschränken? – ctilley79

Antwort

17

Simplest aber nicht die schnellste:

Client.where(:id => Product.select(:client_id).map(&:client_id)) 

SQL Unterabfrage (schneller):

Client.where("EXISTS(SELECT 1 from products where clients.id = products.client_id)") 
+0

Das ist eine viel bessere Antwort, bringt keine unnötigen Spalten zurück, die eine Join-Anweisung enthalten würde. – ctilley79

+0

Ich mag diese Antwort wirklich. Die zweite Abfrage ermöglicht es mir, mit einer nicht aktiven Datensatztabelle zu vergleichen, die sich in derselben Datenbank befindet. – BaneOfSerenity

5

Hier ist eine andere Lösung. Es ist eine Unterabfrage wie Valery zweite Lösung, aber ohne die SQL-Schreiben aus:

Client.where(Product.where(client_id: Client.arel_table[:id]).exists) 
+0

dies funktioniert nicht für mich (mit postgresql adapter); interpretiert den arel_table-Parameter immer als vorbereiteten Wert und dann als Fehler, weil er nicht vorhanden ist. – hoffmanc

+1

Ich habe gerade gelernt, dass '.exists' nicht Teil der öffentlichen API ist. Dies funktionierte bis 4.1, nicht mehr 4.2. – svoop

6

Hier ist die Lösung, die Where Exists gem verwendet (Offenlegung: Ich bin sein Autor):

Client.where_exists(:products) 
+1

Schönes Juwel! Sieht elegant aus! –

+0

Super Arbeit, danke! –