2012-04-13 20 views
15

ich ein Datenbankmodell haben Position(lat,lon) die latitudes und longitudes.Rails Verschachtelte SQL-Abfragen

ich eine Controller-Aktion haben hält show_close_by genannt, die in Grad eine Position recieves (my_lat, my_lon), eine Toleranz (in Kilometern) und sollte die Liste der Positionen zurückkehren in der Datenbank, die innerhalb des Toleranzbereichs liegen.

Dafür verwende ich die hairsine_distance Formel, die die Entfernung in Kilometern (auf der Erdoberfläche) zwischen zwei Koordinaten (lat1, lon1, lat2, lon2) berechnet.

Um die Abfrage schneller zu machen, schrieb ich die ganze haversine_distance Formel in der Abfrage:

... WHERE 2*6371*asin(sqrt(power(sin((:lat2-latitude)*pi()/(180*2)) ,2) + cos(latitude*pi()/180)*cos(:lat2*pi()/180)*power(sin((:lon2-longitude)*pi()/(180*2)),2))) < tolerance 

Die Besonderheiten der Abfrage keine Rolle spielen. Mein Zweifel ist: Ist es notwendig, diese riesige Funktion für JEDE Position in der Datenbank zu berechnen? Kann ich mit einer einfacheren Funktion deutlich zu weit entfernte Positionen herausfiltern?

Nun, ich kann: Mit einer verschachtelten SQL-Abfrage kann ich die Datenbank nach Positionen abfragen, die sich innerhalb eines großen "Quadrats" (in lat/lon) befinden und dann diejenigen mit der teureren trigonometrischen Funktion filtern. Etwas wie folgt aus:

SELECT * FROM (SELECT * FROM Positions WHERE lat-latitude < some_reasonable_upper_bound AND lon-longitude < same_upper_bound) WHERE costly_haversine_distance < tolerance 

Schließlich meine Frage: wie kann ich dies in Rails implementieren (ohne die gesamte Abfrage Schreiben selbst)? Ist Positions.where(reasonable_upper_bound).where(costly_but_accurate_restriction) eine verschachtelte Abfrage? Wenn nicht, wie?

Vielen Dank!

+0

Kennen Sie [Geocoder] (https://github.com/alexreisner/geocoder)? Du installierst den Edelstein, fügst eine Linie in dein Positionsmodell ein und kannst dann Sachen wie 'Position.near ([40.71, 100.23], 20)' machen. Dieses Juwel ist ziemlich populär, also würde ich sagen, dass sie das tun, was du gut machen willst. (sprich, du weißt schon, das Verbinden von 'where'-Klauseln macht nicht das, was du willst. Ich denke, es überschreibt einfach die vorherigen). – Robin

+0

Ja, ich weiß über Geocoder und ich könnte es am Ende benutzen, aber es schien ein bisschen groß für das, was ich will (ich will nur Abstände zwischen Objekten). Wie viel langsamer ist eine App, die ein ganzes Geocoder-Objekt im Vergleich zu der von mir programmierten Barebones-Funktion hairsine_distance lädt? – gdiazc

+0

@Robin Es überschreibt das vorherige nicht, aber es * fügt * die Bedingungen hinzu, die 'AND' zu der gegenwärtigen Abfrage verwenden, die nicht ganz ist, wonach der Fragesteller sucht. – nzifnab

Antwort

25

Hier ist, wie verschachtelte Abfragen zu machen:

LineItem.where(product_id: Product.where(price: 50)) 

Es macht die folgende Anfrage:

SELECT "line_items".* FROM "line_items" 
WHERE "line_items"."product_id" IN 
(SELECT "products"."id" FROM "products" WHERE "products"."price" = 50) 

Beachten Sie, dass nurid s aus dem products Tisch geholt werden. Wenn Sie versuchen, eine andere Verbindung zwischen zwei Entitäten herzustellen, und diese Magie nicht geeignet ist, verwenden Sie Product.select(:some_field).where(...).

+0

Danke für den Beitrag, aber ich brauche wenig andere Hilfe .. Wie schreibe ich Abfrage, wenn ich alle Nachrichten zwischen zwei Benutzer (sagen ID1 & ID2) und Nachricht sender_id und receiver_id kommunizieren müssen. Also muss ich alle Nachrichten auswählen, deren ((sender_id = id1 und reciver_id = id2) oder (sender_id = id2 und reciver_id = id1)) in rails. Ich muss sie aussortieren und paginieren, was nicht gemacht werden kann, wenn ich zwei getrennte Abfragen mache und sie dann addiere (ich werde das gewünschte Ergebnis haben, aber die Paginierung wird schwierig). Bitte helfen Sie mir, indem Sie eine einzelne Zeilenabfrage dafür schreiben. Jede Hilfe wird geschätzt. – zeal

+0

@zeal Versuchen Sie https: // github.com/activerecord-hackery/queel für komplizierte Abfragen. – jdoe

Verwandte Themen