Dlaczego przechowujesz x,y w oddzielnych kolumnach? Zdecydowanie sugeruję, aby zapisać je jako geometry
lub geography
aby uniknąć niepotrzebnego narzutu w czasie zapytania.
Biorąc to pod uwagę, możesz obliczyć i sprawdzić odległości w milach za pomocą ST_DWithin
lub ST_Distance
:
(Dane testowe)
CREATE TABLE building (name text, long numeric, lat numeric);
INSERT INTO building VALUES ('Kirk Michael',-4.5896,54.2835);
INSERT INTO building VALUES ('Baldrine',-4.4077,54.2011);
INSERT INTO building VALUES ('Isle of Man Airport',-4.6283,54.0804);
ST_DZin
ST_DWithin
zwraca wartość true, jeśli dane geometrie znajdują się w określonej odległości od innej. Poniższe zapytanie wyszukuje geometrie znajdujące się w promieniu 5 mil od POINT(-4.6314 54.0887)
:
SELECT name,long,lat,
ST_Distance('POINT(-4.6314 54.0887)'::geography,
ST_MakePoint(long,lat)) * 0.000621371 AS distance
FROM building
WHERE
ST_DWithin('POINT(-4.6314 54.0887)'::geography,
ST_MakePoint(long,lat),8046.72); -- 8046.72 metres = 5 miles;
name | long | lat | distance
---------------------+---------+---------+-------------------
Isle of Man Airport | -4.6283 | 54.0804 | 0.587728347062174
(1 row)
ST_Distance
Funkcja ST_Distance
(z geography
parametry typu) zwróci odległość w metrach . Korzystając z tej funkcji, wszystko, co musisz zrobić, to na końcu przekonwertować metry na mile.
Uwaga :Odległości w zapytaniach przy użyciu ST_Distance
są obliczane w czasie rzeczywistym i dlatego nie używaj indeksu przestrzennego . Dlatego nie zaleca się używania tej funkcji w WHERE
klauzula! Użyj go raczej w SELECT
klauzula. Niemniej jednak poniższy przykład pokazuje, jak można to zrobić:
SELECT name,long,lat,
ST_Distance('POINT(-4.6314 54.0887)'::geography,
ST_MakePoint(long,lat)) * 0.000621371 AS distance
FROM building
WHERE
ST_Distance('POINT(-4.6314 54.0887)'::geography,
ST_MakePoint(long,lat)) * 0.000621371 <= 5;
name | long | lat | distance
---------------------+---------+---------+-------------------
Isle of Man Airport | -4.6283 | 54.0804 | 0.587728347062174
(1 row)
- Uważaj na kolejność parametrów za pomocą
ST_MakePoint
:to długość geograficzna, szerokość geograficzna.. nie na odwrót.
Demo:db<>fiddle
Odpowiednik Amazon Athena (odległość w stopniach):
SELECT *, ST_DISTANCE(ST_GEOMETRY_FROM_TEXT('POINT(-84.386330 33.753746)'),
ST_POINT(long,lat)) AS distance
FROM building
WHERE
ST_Distance(ST_GEOMETRY_FROM_TEXT('POINT(-84.386330 33.753746)'),
ST_POINT(long,lat)) <= 5;