Search code examples
sqlpostgresqllatitude-longitude

How to get all the data in a circle?


I have a table that has column name, latitude, longtitude. I want to find all the data inside a circle, ordered by closest distance to the centre point. To get the circle, I have a centre point (latitude/longtitude). say the latitude and longtitude are -6.12579106 and 106.65699005, then the data that will appear is data that has the names A and B. Below is my table (accident table)

name, latitude, longtitude
A, -6.13116749, 106.66625977
B, -6.10377274, 106.66703224
C, 3.5896654,   98.6738261

I want find data by closest distance in WHERE CLUASE. how to do that? Thanks for the help :)

SELECT * FROM accident
LEFT JOIN polres ON polres.id = accident.polres_id
LEFT JOIN polda ON polda.id = polres.polda_id
WHERE --(condition for find data by closest distance) 

Solution

  • You can use the following function to calculate the distance:

    CREATE OR REPLACE FUNCTION calculate_distance(lat1 float, lon1 float, lat2 float, lon2 float, units varchar)
    RETURNS float AS $dist$
        DECLARE
            dist float = 0;
            radlat1 float;
            radlat2 float;
            theta float;
            radtheta float;
        BEGIN
            IF lat1 = lat2 OR lon1 = lon2
                THEN RETURN dist;
            ELSE
                radlat1 = pi() * lat1 / 180;
                radlat2 = pi() * lat2 / 180;
                theta = lon1 - lon2;
                radtheta = pi() * theta / 180;
                dist = sin(radlat1) * sin(radlat2) + cos(radlat1) * cos(radlat2) * cos(radtheta);
    
                IF dist > 1 THEN dist = 1; END IF;
    
                dist = acos(dist);
                dist = dist * 180 / pi();
                dist = dist * 60 * 1.1515;
    
                IF units = 'K' THEN dist = dist * 1.609344; END IF;
                IF units = 'N' THEN dist = dist * 0.8684; END IF;
    
                RETURN dist;
            END IF;
        END;
    $dist$ LANGUAGE plpgsql;
    

    For units parameter, you can use the following values:

    'M' is statute miles (default)                     
    'K' is kilometers
    'N' is nautical miles
    

    And then use the above function in the following way:

    SELECT * from test where 
    calculate_distance(latitude, longtitude, -6.12579106, 106.65699005, 'K') <3;