Không có chức năng mở rộng không gian địa lý nào trong MySQL hỗ trợ tính toán khoảng cách kinh độ / vĩ độ. Có như MySQL 5,7
.
Bạn đang yêu cầu các vòng tròn lân cận trên bề mặt trái đất. Bạn đề cập trong câu hỏi của mình rằng bạn có giá trị vĩ độ / kinh độ cho mỗi hàng trong flags
của mình bảng và cả Mercator ngang phổ dụng
(UTM) các giá trị dự kiến ở một trong một số vùng UTM
khác nhau . Nếu tôi nhớ chính xác các bản đồ Khảo sát bom mìn ở Vương quốc Anh của mình, thì UTM rất hữu ích để xác định vị trí các mục trên các bản đồ đó.
Việc tính toán khoảng cách giữa hai điểm trong cùng một khu vực là một vấn đề đơn giản trong UTM:khoảng cách Descartes thực hiện thủ thuật. Tuy nhiên, khi các điểm nằm trong các khu vực khác nhau, tính toán đó không hoạt động.
Theo đó, đối với ứng dụng được mô tả trong câu hỏi của bạn, cần phải sử dụng Khoảng cách vòng tròn lớn , được tính bằng hasrsine hoặc một công thức phù hợp khác.
MySQL, được tăng cường với các phần mở rộng không gian địa lý, hỗ trợ một cách để biểu diễn các hình phẳng khác nhau (điểm, đa đường, đa giác, v.v.) dưới dạng nguyên thủy hình học. MySQL 5.6 triển khai một hàm khoảng cách không có tài liệu st_distance(p1, p2)
. Tuy nhiên, hàm này trả về khoảng cách Descartes. Vì vậy, nó hoàn toàn không phù hợp cho các phép tính dựa trên vĩ độ và kinh độ. Ở các vĩ độ ôn đới, một độ vĩ độ phụ gần như gấp đôi khoảng cách bề mặt (bắc-nam) so với một độ kinh độ (đông-tây), bởi vì các đường vĩ độ càng gần nhau càng gần các cực.
Vì vậy, một công thức tiệm cận tròn cần sử dụng vĩ độ và kinh độ chính xác.
Trong ứng dụng của mình, bạn có thể tìm thấy tất cả các flags
các điểm trong vòng mười dặm quy chế tính từ một latpoint,longpoint
nhất định với một truy vấn như sau:
SELECT id, coordinates, name, r,
units * DEGREES(ACOS(LEAST(1.0, COS(RADIANS(latpoint))
* COS(RADIANS(latitude))
* COS(RADIANS(longpoint) - RADIANS(longitude))
+ SIN(RADIANS(latpoint))
* SIN(RADIANS(latitude))))) AS distance
FROM flags
JOIN (
SELECT 42.81 AS latpoint, -70.81 AS longpoint,
10.0 AS r, 69.0 AS units
) AS p ON (1=1)
WHERE MbrContains(GeomFromText (
CONCAT('LINESTRING(',
latpoint-(r/units),' ',
longpoint-(r /(units* COS(RADIANS(latpoint)))),
',',
latpoint+(r/units) ,' ',
longpoint+(r /(units * COS(RADIANS(latpoint)))),
')')), coordinates)
Nếu bạn muốn tìm kiếm các điểm trong vòng 20 km, hãy thay đổi dòng này của truy vấn
20.0 AS r, 69.0 AS units
ví dụ như cái này
20.0 AS r, 111.045 AS units
r
là bán kính mà bạn muốn tìm kiếm. units
là các đơn vị khoảng cách (dặm, km, furlongs, bất cứ thứ gì bạn muốn) trên mỗi độ vĩ độ trên bề mặt trái đất.
Truy vấn này sử dụng lat / long giới hạn cùng với MbrContains
để loại trừ các điểm chắc chắn quá xa so với điểm xuất phát của bạn, sau đó sử dụng công thức khoảng cách vòng tròn lớn để tạo khoảng cách cho các điểm còn lại. Bạn có thể tìm thấy giải thích về tất cả điều này tại đây
. Nếu bảng của bạn sử dụng phương thức truy cập MyISAM và có chỉ mục không gian, MbrContains
sẽ khai thác chỉ mục đó để giúp bạn tìm kiếm nhanh.
Cuối cùng, truy vấn trên chọn tất cả các điểm trong hình chữ nhật. Để thu hẹp điều đó xuống chỉ các điểm trong vòng tròn và sắp xếp chúng theo vùng lân cận, hãy tóm tắt truy vấn như sau:
SELECT id, coordinates, name
FROM (
/* the query above, paste it in here */
) AS d
WHERE d.distance <= d.r
ORDER BY d.distance ASC