Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle räumliche Suche in der Nähe

Sie haben dort eine ziemlich gute Referenz für die mySQL-Distanzsuche.

Vergessen Sie das Oracle Spatial-Zeug. Zu viel Code, zu viel Komplexität, zu wenig Mehrwert.

Hier ist eine Abfrage, die den Zweck erfüllt. Dabei werden Entfernungen in gesetzlichen Meilen verwendet. BEARBEITEN Dies behebt den von mdarwin erwähnten Fehler, auf Kosten der Teilungsüberprüfung, wenn Sie versuchen, es für einen Ort am Nord- oder Südpol zu verwenden.

  SELECT id, city, LATITUDE, LONGITUDE, distance
    FROM
  (
    SELECT id, 
           city, 
           LATITUDE, LONGITUDE,
           (3959 * ACOS(COS(RADIANS(LATITUDE)) 
                 * COS(RADIANS(mylat)) 
                 * COS(RADIANS(LONGITUDE) - RADIANS(mylng)) 
                 + SIN(RADIANS(LATITUDE)) 
                 * SIN(RADIANS(mylat)) 
               ))
           AS distance,
           b.mydst
      FROM Cities
      JOIN (
        SELECT :LAT AS mylat,
               :LONG AS mylng,
               :RADIUS_LIMIT AS mydst
          FROM DUAL
      )b ON (1 = 1)
     WHERE LATITUDE >=  mylat -(mydst/69)
       AND LATITUDE <=  mylat +(mydst/69)
       AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
       AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))
  )a
   WHERE distance <= mydst
   ORDER BY distance

Wenn Sie in Kilometern arbeiten, ändern Sie mydst/69 in mydst/111.045 und 3959 in 6371.4. (1/69 wandelt Meilen in Grad um; 3959 ist ein Wert für den Radius des Planeten.)

Jetzt werden Sie wahrscheinlich versucht sein, diese große Abfrage als „magische Blackbox“ zu verwenden. Tu es nicht! Es ist nicht sehr schwer zu verstehen, und wenn Sie es verstehen, werden Sie in der Lage sein, einen besseren Job zu machen. Folgendes ist los.

Diese Klausel ist das Herzstück dessen, was die Abfrage schnell macht. Es durchsucht Ihre Städtetabelle nach Städten in der Nähe bis zu dem von Ihnen angegebenen Punkt.

     WHERE LATITUDE >=  mylat -(mydst/69)
       AND LATITUDE <=  mylat +(mydst/69)
       AND LONGITUDE >= mylng -(mydst/(69 * COS(RADIANS(mylat))))
       AND LONGITUDE <= mylng +(mydst/(69 * COS(RADIANS(mylat))))

Damit es funktioniert, benötigen Sie auf jeden Fall einen Index für Ihre LATITUDE-Spalte. Ein Index für Ihre LONGITUDE-Spalte hilft auch ein wenig. Es führt eine ungefähre Suche durch und sucht nach Zeilen, die sich innerhalb eines quasi rechteckigen Flecks auf der Erdoberfläche in der Nähe Ihres Punktes befinden. Es wählt zu viele Städte aus, aber nicht viel zu viele.

Mit dieser Klausel hier können Sie die zusätzlichen Städte aus Ihrer Ergebnismenge entfernen:

   WHERE distance <= mydst

Diese Klausel ist die Haversine-Formel, die die Großkreisentfernung zwischen jeder Stadt und Ihrem Punkt berechnet.

           (3959 * ACOS(COS(RADIANS(LATITUDE)) 
                 * COS(RADIANS(mylat)) 
                 * COS(RADIANS(LONGITUDE) - RADIANS(mylng)) 
                 + SIN(RADIANS(LATITUDE)) 
                 * SIN(RADIANS(mylat)) 

Mit dieser Klausel können Sie Ihren Punkt und Ihr Radiuslimit nur einmal als gebundene Variablen in Ihre Abfrage eingeben. Es ist hilfreich, weil die verschiedenen Formeln diese Variablen mehrfach verwenden.

        SELECT :LAT AS mylat,
               :LONG AS mylng,
               :RADIUS_LIMIT AS mydst
          FROM DUAL

Der Rest der Abfrage organisiert einfach Dinge, sodass Sie nach Entfernung auswählen und ordnen können.

Hier ist eine vollständigere Erklärung:http://www.plumislandmedia.net /mysql/haversine-mysql-nächster-ort/