sql >> Database >  >> RDS >> Oracle

Oracle ruimtelijk zoeken op afstand

Je hebt daar een redelijk goede referentie voor het zoeken op afstand via mySQL.

Vergeet de Oracle Spatial-dingen. Te veel code, te veel complexiteit, te weinig toegevoegde waarde.

Hier is een query die het lukt. Hierbij worden afstanden in statuutmijlen gebruikt. BEWERKEN Dit lost de bug op die door mdarwin wordt genoemd, ten koste van het controleren van de verdeling als je het probeert te gebruiken voor een locatie op de noord- of zuidpool.

  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

Als u in kilometers werkt, wijzigt u mydst/69 in mydst/111.045 en wijzigt u 3959 in 6371,4. (1/69 converteert mijlen naar graden; 3959 is een waarde voor de straal van de planeet.)

Nu zult u waarschijnlijk in de verleiding komen om deze grote zoekopdracht te gebruiken als een 'magische zwarte doos'. Doe het niet! Het is niet erg moeilijk te begrijpen, en als je het begrijpt, zul je het beter kunnen doen. Dit is wat er aan de hand is.

Deze clausule is het hart van wat de query snel maakt. Het zoekt in de tabel Steden naar steden in de buurt tot het punt dat u hebt opgegeven.

     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))))

Om het te laten werken, heb je zeker een index nodig in je LATITUDE-kolom. Een index op uw LONGITUDE-kolom zal ook een beetje helpen. Het zoekt bij benadering naar rijen die zich binnen een quasi-rechthoekige plek op het aardoppervlak in de buurt van uw punt bevinden. Het selecteert te veel steden, maar niet veel te veel.

Met deze clausule hier kun je de extra steden uit je resultatenset verwijderen:

   WHERE distance <= mydst

Deze clausule is de haversine-formule die de grootcirkelafstand tussen elke stad en uw punt berekent.

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

Met deze clausule kunt u uw punt en uw straallimiet slechts één keer invoeren als gebonden variabelen voor uw query. Het is handig omdat de verschillende formules die variabelen meerdere keren gebruiken.

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

De rest van de zoekopdracht ordent eenvoudig dingen, zodat u op afstand kunt selecteren en bestellen.

Hier is een meer volledige uitleg:http://www.plumislandmedia.net /mysql/haversine-mysql-nearest-loc/



  1. PHP-script om csv-gegevens in mysql te importeren

  2. Te veel variabelen voor postgegevens?

  3. Hoe EDB de leider werd in de Postgres-markt

  4. in roodverschuiving postgresql kan ik kolommen overslaan met de kopieerfunctie