sql >> Databasteknik >  >> RDS >> Oracle

Oracle rumslig sökning inom avstånd

Du har en ganska bra referens där för mySQL-distanssökning.

Glöm Oracle Spatial-grejer. För mycket kod, för mycket komplexitet, inte tillräckligt med mervärde.

Här är en fråga som kommer att göra susen. Detta använder avstånd i lagstadgade miles. REDIGERA Detta åtgärdar felet som nämns av mdarwin, till priset av delningskontroll om du försöker använda det för en plats vid nord- eller sydpolen.

  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

Om du arbetar i kilometer, ändra mydst/69 till mydst/111.045 och ändra 3959 till 6371.4. (1/69 konverterar miles till grader; 3959 är ett värde för planetens radie.)

Nu kommer du förmodligen att bli frestad att använda den här stora frågan som en "magisk svart låda". Gör det inte! Det är inte särskilt svårt att förstå, och om du förstår det kommer du att kunna göra ett bättre jobb. Här är vad som händer.

Denna klausul är hjärtat i det som gör frågan snabb. Den söker i din stadstabell efter närliggande städer till den punkt du angav.

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

För att det ska fungera behöver du definitivt ett index på din LATITUDE-kolumn. Ett index på din LONGITUDE-kolumn hjälper också lite. Den gör en ungefärlig sökning, letar efter rader som är inom en kvasi-rektangulär fläck på jordens yta nära din punkt. Den väljer ut för många städer, men inte alldeles för många.

Denna klausul här låter dig eliminera de extra städerna från din resultatuppsättning:

   WHERE distance <= mydst

Den här klausulen är haversinformeln som beräknar avståndet i storcirkeln mellan varje stad och din punkt.

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

Den här klausulen låter dig ange din punkt och din radiegräns bara en gång som bundna variabler till din fråga. Det är användbart eftersom de olika formlerna använder dessa variabler flera gånger.

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

Resten av frågan organiserar helt enkelt saker så att du väljer och beställer efter avstånd.

Här är en mer fullständig förklaring:http://www.plumislandmedia.net /mysql/haversine-mysql-nearest-loc/



  1. Använda automation för att påskynda releasetesterna på Galera Cluster med ClusterControl

  2. Oracle PL/SQL:Vidarebefordrar hela raden till procedur från en utlösare

  3. STORT Fel utanför intervallet sedan MySQL 5.5

  4. Python psycopg2 infogas inte i postgresql-tabellen