sql >> Base de Datos >  >> RDS >> Oracle

Búsqueda espacial de Oracle a distancia

Tienes una muy buena referencia allí para la búsqueda de distancia mySQL.

Olvídate de las cosas de Oracle Spatial. Demasiado código, demasiada complejidad, poco valor agregado.

Aquí hay una consulta que hará el truco. Esto utiliza distancias en millas terrestres. EDITAR Esto corrige el error mencionado por mdarwin, a costa de dividir la verificación si intenta usarlo para una ubicación en el polo norte o sur.

  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

Si está trabajando en kilómetros, cambie mydst/69 a mydst/111.045 y cambie 3959 a 6371.4. (1/69 convierte millas a grados; 3959 es un valor para el radio del planeta).

Ahora, probablemente se sienta tentado a usar esta gran consulta como una "caja negra mágica". ¡No lo hagas! No es muy difícil de entender, y si lo entiendes, podrás hacer un mejor trabajo. Esto es lo que está pasando.

Esta cláusula es el corazón de lo que hace que la consulta sea rápida. Busca en su tabla de Ciudades ciudades cercanas al punto que usted especificó.

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

Para que funcione, definitivamente necesita un índice en su columna LATITUD. Un índice en su columna LONGITUD también ayudará un poco. Realiza una búsqueda aproximada, buscando filas que estén dentro de un parche casi rectangular en la superficie de la tierra cerca de su punto. Selecciona demasiadas ciudades, pero no demasiadas.

Esta cláusula aquí le permite eliminar las ciudades adicionales de su conjunto de resultados:

   WHERE distance <= mydst

Esta cláusula es la fórmula haversine que calcula la distancia de círculo máximo entre cada ciudad y su punto.

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

Esta cláusula le permite ingresar su punto y su límite de radio, solo una vez como variables vinculadas a su consulta. Es útil porque las diversas fórmulas usan esas variables varias veces.

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

El resto de la consulta simplemente organiza las cosas para que seleccione y ordene por distancia.

Aquí hay una explicación más completa:http://www.plumislandmedia.net /mysql/haversine-mysql-ubicación-más-cercana/