ค้นหาจุดภายในระยะทางโดยใช้ MySQL


20

ฉันมีตาราง mySQL พร้อมชื่อผู้ใช้ละติจูดและลองจิจูดของผู้ใช้ ฉันต้องการรับรายชื่อผู้ใช้ที่อยู่ในวงกลมหรือสี่เหลี่ยมจัตุรัสของละติจูดและลองจิจูดที่กำหนดตามระยะทางที่กำหนด ตัวอย่างเช่น Lat = 78.3232 และ Long = 65.3234 และ distance = 30 miles ฉันต้องการรับรายชื่อผู้ใช้ที่อยู่ในระยะทาง 30 ไมล์จากจุด 78.3232 และ 65.3234 เป็นไปได้ไหมที่จะแก้ปัญหานี้ด้วยการค้นหาเดี่ยว? หรือคุณสามารถให้คำแนะนำฉันเริ่มแก้แบบสอบถามนี้ได้หรือไม่ ฉันยังใหม่กับข้อมูลทางภูมิศาสตร์


ทำไมไม่ PostGIS หากคุณกำลังเริ่มโครงการทางภูมิศาสตร์คุณยังสามารถเปลี่ยนสแต็กของคุณได้
simplexio

stackoverflow.com/a/40272394/1281385 น่าจะมีประโยชน์ในการเร่งการค้นหานี้ (ถ้าจำเป็น)
exussum

คำตอบ:


32

คำสั่ง SQL ที่จะค้นหาตำแหน่งที่ตั้ง 20 แห่งที่อยู่ในรัศมี 30 ไมล์ไปยังพิกัด 78.3232, 65.3234 มันคำนวณระยะทางตามละติจูด / ลองจิจูดของแถวนั้นและละติจูด / ลองจิจูดเป้าหมายแล้วถามเฉพาะแถวที่ค่าระยะทางน้อยกว่า 30 ไมล์สั่งการค้นหาทั้งหมดตามระยะทางและ จำกัด ผลลัพธ์ไว้ที่ 20 รายการ หากต้องการค้นหาตามกิโลเมตรแทนที่จะเป็นไมล์ให้แทนที่ 3959 ด้วย 6371

SELECT
  id, (
    3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
  ) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

นี่คือการใช้ Google Maps API v3 กับแบ็กเอนด์ MySQL ที่คุณมีอยู่แล้ว

https://developers.google.com/maps/articles/phpsqlsearch_v3#findnearsql


ฉันได้รับข้อผิดพลาดทางไวยากรณ์ในการเลือกของฉันโดยใช้สิ่งนี้ "# 1582 - พารามิเตอร์ที่ไม่ถูกต้องนับในการเรียกไปยังฟังก์ชันดั้งเดิม 'เรเดียน' สิ่งที่มันควรจะเป็น
bluantinoo

พบ: ฉันมีตัวแปร lng ว่างเปล่า! ขออภัย!
bluantinoo

สิ่งที่ฉันต้องการ แต่สิ่งที่ประสิทธิภาพการค้นหาเกินพิกัดสำหรับบันทึกนับพันรายการคืออะไร แล้วความแม่นยำล่ะ?
Amit Shah

1
ดีกว่ามากที่จะแทนที่เป็น 6371392.896 สำหรับการค้นหาโดยเมตร
Vasilii Suricov

34

คำตอบของ Mapperzไม่ถูกต้อง ไซนัสต้องคำนวณจากละติจูดและไม่ใช่จากลองจิจูด ดังนั้นคำสั่ง SQL ที่ถูกต้องคือ:

SELECT
    id, (
      3959 * acos (
      cos ( radians(78.3232) )
      * cos( radians( lat ) )
      * cos( radians( lng ) - radians(65.3234) )
      + sin ( radians(78.3232) )
      * sin( radians( lat ) )
    )
) AS distance
FROM markers
HAVING distance < 30
ORDER BY distance
LIMIT 0 , 20;

คำตอบของคุณควรได้รับคำสั่งที่ 1
Amit Shah

@AmitShah หากคุณคิดว่าคุณสามารถ ping ผู้ถาม (@shihabK ที่ไม่ได้ใช้งานเว็บไซต์เกือบ 6 ปี) และ / หรือโหวตให้กับmeta.stackexchange.com/questions/268666/ …
PolyGeo

นี่ควรเป็นคำตอบที่ยอมรับได้
catbadger

2

มันอาจเป็นฐานในการสร้างฟังก์ชั่น .. เพื่อให้คุณสามารถนำไปใช้ในพื้นที่อื่นได้ ก็จะทำให้แบบสอบถามของคุณสะอาดขึ้นเล็กน้อย ... อย่างน้อยนั่นคือ 2 เซ็นต์ของฉัน

DELIMITER $$

create function calcDistance(lat float, lng float, pnt_lat float, pnt_lng float)

Returns float
BEGIN

Declare dist float;
SET dist =
  3959 * acos (
  cos ( radians(pnt_lat) )
  * cos( radians( lat ) )
  * cos( radians( lng ) - radians(pnt_lng) )
  + sin ( radians(pnt_lat) )
  * sin( radians( lat ) )
);

RETURN dist;

END

คำตอบจะได้รับการอัปเดตถ้าคุณแก้ไขโค้ด มันถูกต้องแล้ว
Vasilii Suricov

0

นี่คือตัวแปรของข้อความค้นหาของฉันดูเหมือนง่ายขึ้นเล็กน้อย ( http://dexxtr.com/post/83498801191/how-to-determine-point-inside-circle-using-mysql )

SELECT 
    *
FROM 
    `locator`
WHERE
    SQRT(POW(X(`center`) - 49.843317 , 2) + POW(Y(`center`) - 24.026642, 2)) * 100 < `radius`

4
มันง่ายกว่า แต่ไม่สนใจข้อเท็จจริงที่ว่าโลกโค้ง
ทิม Rijavec

ต้องการสูตรที่แม่นยำ บางทีนี่อาจเป็นเรื่องดีในระยะทางสั้น ๆ เท่านั้น: D
Jethro

คุณจะเปิดตัวขีปนาวุธหรืออะไร?
Dennis Braga

1
@DennisBraga - ถ้าเป็นเช่นนั้นบางทีคำถามนี้อาจไม่เหมาะสำหรับhttp://globalthermonuclearwar.stackexchange.com ...
ashleedawg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.