2012-04-23 18 views
12

Ich habe zwei Tabellen: Rechtsanwalt und Telefon. Telefon ist in Vorwahl und Nummer getrennt. Ein Anwalt hat viele Telefone. Ich möchte eine Abfrage erzeugen, die nach Rechtsanwälten sucht, die ein Telefon haben, das einem Telefon von einer Liste von Telefonen entspricht.Mehrere oder Bedingungen in ActiveRecord

Wenn ich nur ein Telefon habe, kann ich es wie folgt suchen:

Lawyer.join(:phones).where(:area_code => area_code, :number => number) 

Das Problem ist, dass ich eine Liste mit mehr als einem Bereich Code. Deshalb möchte ich wirklich, so etwas tun:

lawyers = [] 
phones.each { |phone| lawyers += Lawyer.join(:phones).where(:area_code => phone[:area_code], :number => phone[:number]) } 

aber ich möchte nicht, viele Anfragen machen. Kann es nicht in einer einzelnen Abfrageanweisung getan werden?

Edit: So würde ich eine ähnliche Sache mit SQL alleine machen (unter der Annahme, dass die Liste der Zahlen [{: area_code => '555',: number => '1234564'}, {: area_code => ' 533' ,: Zahl => '12345678'}])

select * from phones where (area_code, number) in (('555', '1234564'), ('533', '12345678')) 

Wenn jemand, dass in Active übersetzen lassen, so groß sein würde.

Antwort

13

Wenn Sie ein Array von area_codes übergeben, erstellt AR eine IN-Bedingung. So können Sie Ihre ursprüngliche Suche und Verwendung Arrays verwenden statt:

wo Area_Codes ist ein Array von Area_Codes und Zahlen eine Reihe von Zahlen:

Lawyer.join(:phones).where(:area_code => area_codes, :number => numbers) 

oder:

Lawyer.join(:phones).where("phones.area_code IN (?) AND phones.number IN (?)", area_codes, numbers) 

ergeben sollte:

SELECT * from lawyers JOIN phones ON phones.lawyer_id = lawyers.id WHERE phones.area_code IN (...) AND phones.number IN (...) 
+0

Ich dachte darüber, aber es funktioniert nicht genau wie ich es möchte. Das Problem ist, dass zwei Vorwahlnummern dieselbe Telefonnummer haben könnten. Nehmen wir an, wir suchen nach zwei Telefonen: [{: area_code => 555,: number => 5555555}, {: area_code => 444,: number => 12345678}]. Wenn ich Ihren Ansatz verwende, würde ein Anwalt, der in der Ortsvorwahl 444 mit der Nummer 5555555 wohnt, übereinstimmen. Ich will das nicht. –

+0

Ah, ich sehe dein Problem jetzt. Persönlich würde ich die Daten in eine Spalte "denormalisieren", so dass es suchfreundlicher ist. Ansonsten, ich nehme an, Sie könnten eine Where-Bedingung erstellen, indem Sie jeden Code und jede Nummer wiederholen, aber ich mag diese Lösung viel weniger. – miked

+1

Es ist einfach, dies in SQL zu tun: Wählen Sie * von Telefonen wo (Area_code, Nummer) in ((555 ',' 5555555 '), (' 444 ',' 12345678 ')) Also gibt es wirklich keinen Grund, Daten zu denormalisieren. Ich muss nur das in ActiveRecord übersetzen. –

0
Lawyer.join(:phones).where(
    "(phones.area_code, phones.number) IN (('555', '5555555'), ('444', '12345678'))" 
)