ค้นหาละติจูด / ลองจิจูดที่ใกล้ที่สุดด้วยการสืบค้น SQL


173

ฉันมีละติจูดและลองจิจูดและฉันต้องการดึงระเบียนจากฐานข้อมูลซึ่งมีละติจูดและลองจิจูดที่ใกล้ที่สุดตามระยะทางถ้าระยะทางนั้นยาวเกินกว่าที่กำหนดไว้

โครงสร้างตาราง:

id
latitude
longitude
place name
city
country
state
zip
sealevel

1
นี่เป็นคำถามซ้ำซ้อนของคำถามการค้นหาใกล้เคียง
Darius Bacon

1
มีชุดของภาพนิ่งโดย Alexander Rubin บนGeo (ความใกล้ชิด) ค้นหาด้วย MySQL (ลิงค์ PDF)
Martijn Pieters

คำตอบ:


209
SELECT latitude, longitude, SQRT(
    POW(69.1 * (latitude - [startlat]), 2) +
    POW(69.1 * ([startlng] - longitude) * COS(latitude / 57.3), 2)) AS distance
FROM TableName HAVING distance < 25 ORDER BY distance;

โดยที่[starlat]และ[startlng]เป็นตำแหน่งที่จะเริ่มวัดระยะทาง


49
เพียงบันทึกประสิทธิภาพจะดีที่สุดที่จะไม่ sqrt ตัวแปรระยะทาง แต่แทนที่จะเป็นสี่เหลี่ยมค่าการทดสอบ '25' ... ภายหลัง sqrt ผลลัพธ์ที่ได้ผ่านไปถ้าคุณต้องการที่จะแสดงระยะทาง
sradforth

9
สิ่งที่จะเป็นแบบสอบถามเดียวกันสำหรับระยะทางที่จะอยู่ในหน่วยเมตร? (ซึ่งปัจจุบันเป็นไมล์ใช่มั้ย)
http

8
วัดอะไรที่ 25
Steffan Donal

16
เพื่ออธิบายให้ชัดเจนที่นี่ 69.1 คือปัจจัยการแปลงไมล์เป็นองศาละติจูด 57.3 มีค่าประมาณ 180 / pi ดังนั้นการแปลงจากองศาเป็นเรเดียนสำหรับฟังก์ชันโคไซน์ 25 คือรัศมีการค้นหาในหน่วยไมล์ นี่คือสูตรที่จะใช้เมื่อใช้องศาทศนิยมและไมล์เทพ
John Vance

8
นอกจากนี้มันไม่ได้คำนึงถึงความโค้งของโลก นี่จะไม่เป็นปัญหาสำหรับรัศมีการค้นหาสั้น ๆ มิฉะนั้นคำตอบของอีวานและอิกอร์จะสมบูรณ์กว่า
John Vance

63

โซลูชันของ Google:

สร้างตาราง

เมื่อคุณสร้างตาราง MySQL คุณต้องการให้ความสนใจเป็นพิเศษกับแอตทริบิวต์ lat และ lng ด้วยความสามารถในการซูมปัจจุบันของ Google แผนที่คุณควรต้องการความแม่นยำ 6 หลักหลังจุดทศนิยม เพื่อรักษาพื้นที่เก็บข้อมูลที่จำเป็นสำหรับตารางของคุณให้น้อยที่สุดคุณสามารถระบุว่าแอตทริบิวต์ lat และ lng เป็นขนาดลอยตัว (10,6) นั่นจะทำให้เขตข้อมูลเก็บ 6 หลักหลังจุดทศนิยมบวกได้สูงสุด 4 หลักก่อนจุดทศนิยมเช่น -123.456789 องศา ตารางของคุณควรมีแอตทริบิวต์ id เพื่อใช้เป็นคีย์หลัก

CREATE TABLE `markers` (
  `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
  `name` VARCHAR( 60 ) NOT NULL ,
  `address` VARCHAR( 80 ) NOT NULL ,
  `lat` FLOAT( 10, 6 ) NOT NULL ,
  `lng` FLOAT( 10, 6 ) NOT NULL
) ENGINE = MYISAM ;

การเติมตาราง

หลังจากสร้างตารางได้เวลารวบรวมข้อมูล ข้อมูลตัวอย่างด้านล่างนี้มีไว้สำหรับประมาณ 180 พิซซ่ากระจายอยู่ทั่วสหรัฐอเมริกา ใน phpMyAdmin คุณสามารถใช้แท็บนำเข้าเพื่อนำเข้ารูปแบบไฟล์ต่าง ๆ รวมถึง CSV (ค่าที่คั่นด้วยเครื่องหมายจุลภาค) Microsoft Excel และ Google Spreadsheets ส่งออกเป็นรูปแบบ CSV ดังนั้นคุณสามารถถ่ายโอนข้อมูลจากสเปรดชีตไปยังตาราง MySQL ได้อย่างง่ายดายผ่านการส่งออก / นำเข้าไฟล์ CSV

INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Frankie Johnnie & Luigo Too','939 W El Camino Real, Mountain View, CA','37.386339','-122.085823');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Amici\'s East Coast Pizzeria','790 Castro St, Mountain View, CA','37.38714','-122.083235');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Kapp\'s Pizza Bar & Grill','191 Castro St, Mountain View, CA','37.393885','-122.078916');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Round Table Pizza: Mountain View','570 N Shoreline Blvd, Mountain View, CA','37.402653','-122.079354');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Tony & Alba\'s Pizza & Pasta','619 Escuela Ave, Mountain View, CA','37.394011','-122.095528');
INSERT INTO `markers` (`name`, `address`, `lat`, `lng`) VALUES ('Oregano\'s Wood-Fired Pizza','4546 El Camino Real, Los Altos, CA','37.401724','-122.114646');

การค้นหาตำแหน่งด้วย MySQL

ในการค้นหาตำแหน่งในตารางตัวทำเครื่องหมายของคุณที่อยู่ในระยะรัศมีที่กำหนดของละติจูด / ลองจิจูดที่กำหนดคุณสามารถใช้คำสั่ง SELECT ตามสูตร Haversine สูตรฮาวาซีนใช้โดยทั่วไปสำหรับการคำนวณระยะทางวงกลมใหญ่ระหว่างพิกัดสองคู่บนทรงกลม คำอธิบายทางคณิตศาสตร์ในเชิงลึกนั้นได้รับจาก Wikipedia และการอภิปรายที่ดีเกี่ยวกับสูตรที่เกี่ยวข้องกับการเขียนโปรแกรมนั้นอยู่ในเว็บไซต์ของ Movable Type

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

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

อันนี้คือการหาละติจูดและลองจิจูดในระยะทางน้อยกว่า 28 ไมล์

อีกอันหนึ่งคือค้นหาพวกมันในระยะห่างระหว่าง 28 ถึง 29 ไมล์:

SELECT 
id, 
(
   3959 *
   acos(cos(radians(37)) * 
   cos(radians(lat)) * 
   cos(radians(lng) - 
   radians(-122)) + 
   sin(radians(37)) * 
   sin(radians(lat )))
) AS distance 
FROM markers 
HAVING distance < 29 and distance > 28 
ORDER BY distance LIMIT 0, 20;

https://developers.google.com/maps/articles/phpsqlsearch_v3#creating-the-map


1
มันควรจะเป็นอย่างนั้นหรือไม่HAVING distance < 25เมื่อเราทำการค้นหาสถานที่ภายในรัศมี 25 ไมล์
Vitalii Elenhaupt

มันควร> 25 แล้วมันจะค้นหาระเบียนทั้งหมด
vidur punj

คุณแน่ใจ @vidurpunj เกี่ยวกับ> 25 หรือไม่
Amranur Rahman

ฉันลองใช้คำสั่ง sql โดยใช้: distance <25 แต่ไม่พบผลลัพธ์ .. เนื่องจากเครื่องหมายระยะทางทั้งหมดอยู่เหนือ 25 ...
IbrahimShendy

พิกัด 37, -122 เป็นละติจูดและลองจิจูดสำหรับตำแหน่งจากที่เราต้องการหาระยะทางหรือไม่?
Prasobh.Kollattu

28

นี่เป็นวิธีแก้ปัญหาของฉันเต็มนำมาใช้ใน PHP

การแก้ปัญหานี้ใช้สูตร Haversine ที่แสดงอยู่ในhttp://www.scribd.com/doc/2569355/Geo-Distance-Search-with-MySQL

ควรสังเกตว่าสูตร Haversine มีจุดอ่อนรอบ ๆ ขั้ว คำตอบนี้แสดงวิธีการใช้สูตรระยะทางวงเวียนใหญ่ vincentyเพื่อให้ได้สิ่งนี้อย่างไรก็ตามฉันเลือกที่จะใช้ Haversine เพราะมันดีพอสำหรับวัตถุประสงค์ของฉัน

ฉันกำลังจัดเก็บละติจูดเป็น DECIMAL (10,8) และลองจิจูดเป็น DECIMAL (11,8) หวังว่านี่จะช่วยได้!

showClosest.php

<?PHP
/**
 * Use the Haversine Formula to display the 100 closest matches to $origLat, $origLon
 * Only search the MySQL table $tableName for matches within a 10 mile ($dist) radius.
 */
include("./assets/db/db.php"); // Include database connection function
$db = new database(); // Initiate a new MySQL connection
$tableName = "db.table";
$origLat = 42.1365;
$origLon = -71.7559;
$dist = 10; // This is the maximum distance (in miles) away from $origLat, $origLon in which to search
$query = "SELECT name, latitude, longitude, 3956 * 2 * 
          ASIN(SQRT( POWER(SIN(($origLat - latitude)*pi()/180/2),2)
          +COS($origLat*pi()/180 )*COS(latitude*pi()/180)
          *POWER(SIN(($origLon-longitude)*pi()/180/2),2))) 
          as distance FROM $tableName WHERE 
          longitude between ($origLon-$dist/cos(radians($origLat))*69) 
          and ($origLon+$dist/cos(radians($origLat))*69) 
          and latitude between ($origLat-($dist/69)) 
          and ($origLat+($dist/69)) 
          having distance < $dist ORDER BY distance limit 100"; 
$result = mysql_query($query) or die(mysql_error());
while($row = mysql_fetch_assoc($result)) {
    echo $row['name']." > ".$row['distance']."<BR>";
}
mysql_close($db);
?>

./assets/db/db.php

<?PHP
/**
 * Class to initiate a new MySQL connection based on $dbInfo settings found in dbSettings.php
 *
 * @example $db = new database(); // Initiate a new database connection
 * @example mysql_close($db); // close the connection
 */
class database{
    protected $databaseLink;
    function __construct(){
        include "dbSettings.php";
        $this->database = $dbInfo['host'];
        $this->mysql_user = $dbInfo['user'];
        $this->mysql_pass = $dbInfo['pass'];
        $this->openConnection();
        return $this->get_link();
    }
    function openConnection(){
    $this->databaseLink = mysql_connect($this->database, $this->mysql_user, $this->mysql_pass);
    }

    function get_link(){
    return $this->databaseLink;
    }
}
?>

./assets/db/dbSettings.php

<?php
$dbInfo = array(
    'host'      => "localhost",
    'user'      => "root",
    'pass'      => "password"
);
?>

อาจเป็นไปได้ที่จะเพิ่มประสิทธิภาพโดยใช้โพรซีเดอร์ที่เก็บ MySQL ตามคำแนะนำของบทความ "Geo-Distance-Search-with-MySQL" ที่โพสต์ไว้ด้านบน

ฉันมีฐานข้อมูลประมาณ ~ 17,000 แห่งและเวลาดำเนินการค้นหาคือ 0.054 วินาที


ฉันจะหาระยะทางเป็นกิโลเมตรหรือเมตรได้อย่างไร ความนับถือ!
chemitaxis

2
ไมล์ * 1.609344 = km
Sinan Dizdarević

2
คำเตือน. โซลูชัน Excelent แต่มีข้อบกพร่อง ทั้งหมดabsจะถูกลบออก ไม่จำเป็นต้องใช้ค่า abs เมื่อแปลงจากองศาเป็นเรเดียนและแม้ว่าคุณจะทำคุณกำลังทำมันเป็นเพียงหนึ่งในละติจูด โปรดแก้ไขเพื่อแก้ไขข้อผิดพลาด
Chango

1
และสำหรับใครก็ตามที่ต้องการสิ่งนี้ในหน่วยเมตร: แปลง 3956 ไมล์เป็นกิโลเมตร: รัศมีของโลก; แปลง 69 ไมล์เป็นกิโลเมตร: ความยาวaproxímateละติจูด 1 องศาในกม.; และป้อนระยะทางเป็นกิโลเมตร
Chango

1
และแทนที่69ด้วย111,044736(ลืมไปว่าในความคิดเห็นด้านบน)
rkeet

24

ในกรณีที่คุณขี้เกียจเหมือนฉันนี่คือคำตอบที่รวมกันจากคำตอบนี้และคำตอบอื่น ๆ ของ SO

set @orig_lat=37.46; 
set @orig_long=-122.25; 
set @bounding_distance=1;

SELECT
*
,((ACOS(SIN(@orig_lat * PI() / 180) * SIN(`lat` * PI() / 180) + COS(@orig_lat * PI() / 180) * COS(`lat` * PI() / 180) * COS((@orig_long - `long`) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS `distance` 
FROM `cities` 
WHERE
(
  `lat` BETWEEN (@orig_lat - @bounding_distance) AND (@orig_lat + @bounding_distance)
  AND `long` BETWEEN (@orig_long - @bounding_distance) AND (@orig_long + @bounding_distance)
)
ORDER BY `distance` ASC
limit 25;

1
สิ่งที่ไม่bounding_distanceเป็นตัวแทน? ค่านี้ จำกัด ผลลัพธ์เป็นจำนวนไมล์หรือไม่ ดังนั้นในกรณีนี้จะส่งคืนผลลัพธ์ภายใน 1 ไมล์
James

1
@ bounding_distance มีหน่วยเป็นองศาที่นี่และใช้เพื่อเร่งการคำนวณโดย จำกัด ขอบเขตการค้นหาที่มีประสิทธิภาพ ตัวอย่างเช่นหากคุณรู้ว่าผู้ใช้ของคุณอยู่ในเมืองใดเมืองหนึ่งและคุณรู้ว่าคุณมีจุดภายในเมืองไม่กี่จุดคุณสามารถกำหนดระยะขอบเขตของคุณได้อย่างปลอดภัย
Evan

1
สูตรนี้ใช้ระยะทางภูมิศาสตร์อะไร
bbodenmiller

12

ง่าย ๆ ;)

SELECT * FROM `WAYPOINTS` W ORDER BY
ABS(ABS(W.`LATITUDE`-53.63) +
ABS(W.`LONGITUDE`-9.9)) ASC LIMIT 30;

เพียงแค่แทนที่พิกัดด้วยค่าที่คุณต้องการ ค่าจะต้องเก็บไว้เป็นสองเท่า นี่เป็นตัวอย่าง MySQL 5.x ที่ใช้งานได้

ไชโย


2
ไม่มีความคิดว่าทำไม upvote, OP ต้องการ จำกัด และสั่งซื้อตามระยะทางที่แน่นอนไม่ จำกัด โดย 30 และสั่งซื้อโดย dx+dy
okm

3
มันทำเพื่อฉัน มันไม่ใช่สิ่งที่ OP ต้องการ แต่เป็นสิ่งที่ฉันต้องการดังนั้นขอบคุณสำหรับการตอบ! :)
ผู้ดูแลเว็บ G

ABS ด้านนอกสุดเพียงพอ)
dzona

6

ลองสิ่งนี้มันจะแสดงจุดที่ใกล้ที่สุดเพื่อให้พิกัด (ภายใน 50 กม.) มันทำงานได้อย่างสมบูรณ์แบบ:

SELECT m.name,
    m.lat, m.lon,
    p.distance_unit
             * DEGREES(ACOS(COS(RADIANS(p.latpoint))
             * COS(RADIANS(m.lat))
             * COS(RADIANS(p.longpoint) - RADIANS(m.lon))
             + SIN(RADIANS(p.latpoint))
             * SIN(RADIANS(m.lat)))) AS distance_in_km
FROM <table_name> AS m
JOIN (
      SELECT <userLat> AS latpoint, <userLon> AS longpoint,
             50.0 AS radius, 111.045 AS distance_unit
     ) AS p ON 1=1
WHERE m.lat
BETWEEN p.latpoint  - (p.radius / p.distance_unit)
    AND p.latpoint  + (p.radius / p.distance_unit)
    AND m.lon BETWEEN p.longpoint - (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
    AND p.longpoint + (p.radius / (p.distance_unit * COS(RADIANS(p.latpoint))))
ORDER BY distance_in_km

<table_name>การเปลี่ยนแปลงเพียง <userLat>และ<userLon>

คุณสามารถอ่านเพิ่มเติมเกี่ยวกับโซลูชันนี้ได้ที่นี่: http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/


6

คำตอบดั้งเดิมของคำถามนั้นดี แต่ mysql รุ่นใหม่กว่า (MySQL 5.7.6 บน) รองรับการค้นหาทางภูมิศาสตร์ดังนั้นตอนนี้คุณสามารถใช้ฟังก์ชันที่มีอยู่แล้วภายในแทนที่จะใช้คำสั่งที่ซับซ้อน

ตอนนี้คุณสามารถทำสิ่งที่ชอบ:

select *, ST_Distance_Sphere( point ('input_longitude', 'input_latitude'), 
                              point(longitude, latitude)) * .000621371192 
          as `distance_in_miles` 
  from `TableName`
having `distance_in_miles` <= 'input_max_distance'
 order by `distance_in_miles` asc

metersผลที่จะได้กลับมาใน ดังนั้นหากคุณต้องการKMเพียงแค่ใช้.001แทน.000621371192 (ซึ่งก็คือสำหรับไมล์)

MySql docs อยู่ที่นี่


หากเป็นไปได้โปรดเพิ่มรุ่น mysql ในคำตอบ
Parixit

ST_Distance_Sphereไม่มีอยู่ในการติดตั้งของโฮสต์ ( mysql Ver 15.1 Distrib 10.2.23-MariaDB) ฉันอ่านที่อื่นเพื่อทดแทนST_Distanceแต่ระยะทางก็ห่างกัน
ashleedawg

@ashleedawg - จากเวอร์ชันฉันคิดว่าคุณใช้ MariaDB ซึ่งเป็นส่วนหนึ่งของ mysql จากการสนทนานี้ดูเหมือนว่า MariaDB ยังไม่ได้ใช้งานST_Distance_Sphere
Sherman

5

คุณกำลังมองหาสิ่งต่าง ๆ เช่น สูตรแฮเวอรีน ดูที่นี่เช่นกัน

มีคนอื่น แต่นี่คือการอ้างถึงมากที่สุด

หากคุณกำลังมองหาบางสิ่งที่มีประสิทธิภาพยิ่งขึ้นคุณอาจต้องการดูความสามารถของ GIS ในฐานข้อมูลของคุณ พวกเขาสามารถทำสิ่งที่ยอดเยี่ยมบางอย่างเช่นบอกคุณว่ามีจุด (เมือง) ปรากฏอยู่ในรูปหลายเหลี่ยมที่กำหนด (ภูมิภาคประเทศประเทศทวีป)


เป็นบทความที่ถูกอ้างถึงมากที่สุด แต่มีหลายบทความที่อ้างถึงฮาร์ดแวร์คอมพิวเตอร์เก่าเมื่อพูดถึงคำสั่งเกี่ยวกับการคำนวณที่ไม่ถูกต้องโดยใช้วิธีอื่น ดูเพิ่มเติมที่movable-type.co.uk/scripts/latlong.html#cosine-law
Arjan

4

ตรวจสอบรหัสนี้ตามบทความGeo-Distance-Search-with-MySQL :

ตัวอย่าง: ค้นหาโรงแรมที่ใกล้ที่สุด 10 แห่งไปยังที่ตั้งปัจจุบันของฉันในรัศมี 10 ไมล์:

#Please notice that (lat,lng) values mustn't be negatives to perform all calculations

set @my_lat=34.6087674878572; 
set @my_lng=58.3783670308302;
set @dist=10; #10 miles radius

SELECT dest.id, dest.lat, dest.lng,  3956 * 2 * ASIN(SQRT(POWER(SIN((@my_lat -abs(dest.lat)) * pi()/180 / 2),2) + COS(@my_lat * pi()/180 ) * COS(abs(dest.lat) *  pi()/180) * POWER(SIN((@my_lng - abs(dest.lng)) *  pi()/180 / 2), 2))
) as distance
FROM hotel as dest
having distance < @dist
ORDER BY distance limit 10;

#Also notice that distance are expressed in terms of radius.

3
simpledb.execSQL("CREATE TABLE IF NOT EXISTS " + tablename + "(id INTEGER PRIMARY KEY   AUTOINCREMENT,lat double,lng double,address varchar)");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2891001','70.780154','craftbox');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2901396','70.7782428','kotecha');");//22.2904718 //70.7783906
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2863155','70.772108','kkv Hall');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.275993','70.778076','nana mava');");
            simpledb.execSQL("insert into '" + tablename + "'(lat,lng,address)values('22.2667148','70.7609386','Govani boys hostal');");


    double curentlat=22.2667258;  //22.2677258
    double curentlong=70.76096826;//70.76096826

    double curentlat1=curentlat+0.0010000;
    double curentlat2=curentlat-0.0010000;

    double curentlong1=curentlong+0.0010000;
    double curentlong2=curentlong-0.0010000;

    try{

        Cursor c=simpledb.rawQuery("select * from '"+tablename+"' where (lat BETWEEN '"+curentlat2+"' and '"+curentlat1+"') or (lng BETWEEN         '"+curentlong2+"' and '"+curentlong1+"')",null);

        Log.d("SQL ", c.toString());
        if(c.getCount()>0)
        {
            while (c.moveToNext())
            {
                double d=c.getDouble(1);
                double d1=c.getDouble(2);

            }
        }
    }
    catch (Exception e)
    {
        e.printStackTrace();
    }

2

ดูเหมือนว่าคุณต้องการค้นหาเพื่อนบ้านที่ใกล้ที่สุดโดยมีระยะทาง จำกัด SQL ไม่สนับสนุนอะไรเช่นนี้เท่าที่ผมทราบและคุณจะต้องใช้โครงสร้างข้อมูลทางเลือกเช่นR-ต้นไม้หรือต้นไม้ kd


2

ค้นหาผู้ใช้ที่ใกล้ที่สุดไปยังของฉัน:

ระยะทางเป็นเมตร

อยู่ในสูตรของ Vincenty

ฉันมีตารางผู้ใช้:

+----+-----------------------+---------+--------------+---------------+
| id | email                 | name    | location_lat | location_long |
+----+-----------------------+---------+--------------+---------------+
| 13 | xxxxxx@xxxxxxxxxx.com | Isaac   | 17.2675625   | -97.6802361   |
| 14 | xxxx@xxxxxxx.com.mx   | Monse   | 19.392702    | -99.172596    |
+----+-----------------------+---------+--------------+---------------+

SQL:

-- my location:  lat   19.391124   -99.165660
SELECT 
(ATAN(
    SQRT(
        POW(COS(RADIANS(users.location_lat)) * SIN(RADIANS(users.location_long) - RADIANS(-99.165660)), 2) +
        POW(COS(RADIANS(19.391124)) * SIN(RADIANS(users.location_lat)) - 
       SIN(RADIANS(19.391124)) * cos(RADIANS(users.location_lat)) * cos(RADIANS(users.location_long) - RADIANS(-99.165660)), 2)
    )
    ,
    SIN(RADIANS(19.391124)) * 
    SIN(RADIANS(users.location_lat)) + 
    COS(RADIANS(19.391124)) * 
    COS(RADIANS(users.location_lat)) * 
    COS(RADIANS(users.location_long) - RADIANS(-99.165660))
 ) * 6371000) as distance,
users.id
FROM users
ORDER BY distance ASC

รัศมีของโลก: 6371000 (เป็นเมตร)


1

MS SQL Edition ที่นี่:

        DECLARE @SLAT AS FLOAT
        DECLARE @SLON AS FLOAT

        SET @SLAT = 38.150785
        SET @SLON = 27.360249

        SELECT TOP 10 [LATITUDE], [LONGITUDE], SQRT(
            POWER(69.1 * ([LATITUDE] - @SLAT), 2) +
            POWER(69.1 * (@SLON - [LONGITUDE]) * COS([LATITUDE] / 57.3), 2)) AS distance
        FROM [TABLE] ORDER BY 3

0

ดูเหมือนว่าคุณควรใช้ PostGIS, SpatialLite, SQLServer2008 หรือ Oracle Spatial พวกเขาทุกคนสามารถตอบคำถามนี้ให้กับคุณด้วย SQL เชิงพื้นที่


7
ดูเหมือนว่าคุณไม่ควรแนะนำให้ผู้คนเปลี่ยนแพลตฟอร์มฐานข้อมูลทั้งหมดของพวกเขาและทำให้ผลลัพธ์ที่ไม่เกี่ยวข้องปรากฏขึ้นในการค้นหา google ของฉันเมื่อฉันค้นหา "Oracle" โดยเด็ดขาด ...
ฉันปล้ำหมีหนึ่งครั้ง

0

ในกรณีที่รุนแรงวิธีนี้ล้มเหลว แต่เพื่อประสิทธิภาพฉันได้ข้ามตรีโกณมิติและคำนวณค่าทแยงมุมยกกำลังสอง


-13

ปัญหานี้ไม่ยากเลย แต่จะซับซ้อนกว่านี้ถ้าคุณต้องการปรับให้เหมาะสม

สิ่งที่ฉันหมายถึงคือคุณมีที่ตั้ง 100 แห่งในฐานข้อมูลของคุณหรือ 100 ล้านแห่ง? มันทำให้เกิดความแตกต่างใหญ่

หากจำนวนที่ตั้งมีขนาดเล็กให้ลบออกจาก SQL และใส่รหัสโดยทำ ->

Select * from Location

เมื่อคุณได้รับพวกเขาเป็นรหัสให้คำนวณระยะทางระหว่าง lat / lon และต้นฉบับของคุณด้วยสูตร Haversine และเรียงลำดับ

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