Trả lại tất cả kết quả trong bán kính 30km của một điểm lat / long cụ thể?


21

Tôi có một bảng với một cột the_geomchứa dữ liệu tương tự:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

Mà khi áp dụng hàm ST_AsEWKT(the_geom)trả về:

SRID=4326;POLYGON((7.5077921782085 46.9082092877942,7.53493597966353 46.9081898840296,7.53496566473541 46.9249119938446,7.50781341296434 46.9249314035307,7.5077921782085 46.9082092877942))

Tôi cần chọn tất cả dữ liệu trong bán kính 30km của một điểm lat / long cụ thể, ví dụ:

  • lat = 46.8167
  • lng = 6,9333

Tuy nhiên, bất cứ khi nào tôi cố gắng sử dụng ST_Distance(), tôi luôn nhận được các giá trị nhỏ hơn 1 và sử dụng ST_DWithin()luôn được trả về đúng.

Câu trả lời:


23

Vui lòng kiểm tra truy vấn sau đây cho PostgreSQL để nhận dữ liệu trong khoảng cách nhất định. Tôi mong nó sẽ có ích.

SELECT *
FROM your_table
WHERE ST_Distance_Sphere(the_geom, ST_MakePoint(your_lon,your_lat)) <= radius_mi * 1609.34

1
Đã có thể làm cho nó hoạt động với: CHỌN * TỪ myTable WHERE GeometryType (ST_Centroid (the_geom)) = 'POINT' AND ST_Distance_Sphere (ST_Point (ST_X (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom) , 46.8167))) <= 18 * 1609.34
dan2k3k4

Thật tuyệt :)
Farhat Abbas

2
Chỉ cần cho bất cứ ai khác tự hỏi, con số 1609,34 là mét trên mỗi dặm, đó là các postgres đơn vị cơ sở đang sử dụng. Vì vậy, để làm số km, rõ ràng là nhân với 1000.
1mike12

2
Ghi chú Pedantic: chính xác là 1609.344 (theo định nghĩa)
barrycarter

6

Có vẻ như bạn đang lưu trữ hình học của mình trong một cột hình học chứ không phải cột địa lý.
Điều đó là tốt, nhưng hàm ST_Distance sẽ trả về các phép đo theo đơn vị chiếu thay vì luôn luôn là mét. Trong trường hợp của bạn (4326), đó sẽ là độ.
Chỉ sử dụng bộ đệm với ST_Within cũng không hoạt động, vì ST_Buffer cũng sẽ được đo bằng độ.

Bạn có thể chuyển đổi dữ liệu của mình để sử dụng địa lý thay vì hình học hoặc bạn có thể chuyển đổi điểm của mình thành một số phép chiếu sử dụng mét, bộ đệm, sau đó chuyển đổi trở lại thành 4326 để xem những gì bên trong nó:

SELECT
    *
FROM <your data>
WHERE ST_Within(the_geom, 
                ST_Transform(ST_Buffer(ST_Transform(ST_SetSRID(ST_MakePoint(6.9333, 46.8167), 4326), 3857), 30000), 4326)) = 1

Đó là dự án vào năm 3857 , đây là một phép chiếu phổ biến với các bản đồ web. Sau đó, nó đệm nó 30.000 mét sau đó chuyển hướng trở lại thành 4326 trước khi chuyển nó sang ST_Within.


Ngoại trừ một Mercator giả không đáng tin cậy về khoảng cách, vì vậy trừ khi dữ liệu gần với đường xích đạo, kết quả sẽ bị tắt, đặc biệt là với khoảng cách 30km.
Vince

6

Trong thế giới của tôi, sử dụng SRID tùy chỉnh (cho Google Maps), một cái gì đó như thế này đã hoạt động:

SELECT * FROM addresses WHERE ST_DWithin(location, ST_SetSRID(ST_MakePoint(longitude, latitude), 3785), radius);

trong đó loại locationlà hình học (Điểm, 3785) và longitude, latituderadiuslà hình nổi (ví dụ -100, 44, 30 cho 100W / 44N / 30 "đơn vị" - xem bên dưới)

Xem cách tốt nhất để tìm tất cả các đối tượng trong bán kính của một đối tượng khác là gì? trong các tài liệu postgis:

Các ST_DWithin(geometry, geometry, distance)chức năng là một cách tiện dụng thực hiện một tìm kiếm khoảng cách lập chỉ mục. Nó hoạt động bằng cách tạo một hình chữ nhật tìm kiếm đủ lớn để bao quanh bán kính khoảng cách, sau đó thực hiện tìm kiếm khoảng cách chính xác trên tập hợp con kết quả được lập chỉ mục.

UPDATE: đơn vị không phải là dặm cho SRID 3785 ... họ dường như là một trong hai radian hoặc độ hoặc một cái gì đó như thế. Nhưng đặc điểm kỹ thuật cho SRID của tôi nói rằng các đơn vị của nó là mét hoặc độ và nó chắc chắn không phải là một trong số đó, ít nhất là không có một số chuyển đổi:

alex=# select * from spatial_ref_sys where srid=3785; srid | auth_name | auth_srid | srtext | proj4text
3785 | EPSG | 3785 | PROJCS["Popular Visualisation CRS / Mercator (deprecated)",GEOGCS["Popular Visualisation CRS",DATUM["Popular_Visualisation_Datum",SPHEROID["Popular Visualisation Sphere",6378137,0,AUTHORITY["EPSG","7059"]],TOWGS84[0,0,0,0,0,0,0],AUTHORITY["EPSG","6055"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4055"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Mercator_1SP"],PARAMETER["central_meridian",0],PARAMETER["scale_factor",1],PARAMETER["false_easting",0],PARAMETER["false_northing",0],EXTENSION["PROJ4","+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"],AUTHORITY["EPSG","3785"],AXIS["X",EAST],AXIS["Y",NORTH]] | +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs


Sự khác biệt giữa 3785 (trong bài viết của bạn) và 3857 là gì?
điều chỉnh

Chúng là những dự đoán khác nhau. 3875 so với 3857 - Tôi không biết nếu cái này tốt hơn cái khác
AlexChaffee

1
"EPSG 3785 đã không được ủng hộ đối với EPSG 3857 giống hệt nhau" - github.com/rgeo/rgeo/pull/61
Yarin

2

Tôi nghĩ rằng điều này sẽ làm việc:

SELECT gid FROM table 
WHERE ST_DWithin(the_geom, ST_SetSRID(ST_Point(6.9333, 46.8167), 4326), 30000)

3
nếu bạn truyền the_geom vào địa lý sẽ hoạt động. st_dwithin (địa lý (the_geom), địa lý (<Point, 4326>), 30000)
cavila
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.