ส่งคืนผลลัพธ์ทั้งหมดภายในรัศมี 30 กม. ของจุดละติจูด / ลองจิจูดเฉพาะหรือไม่


21

ฉันมีตารางที่มีคอลัมน์the_geomซึ่งมีข้อมูลคล้ายกับ:

0103000020E61000000100000005000000CE473AACFA071E40F27FB23340744740336FE841C6231E40873BED903F744740FC150A0ACE231E40D19E2684637647409C9B443D00081E409A9AF82664764740CE473AACFA071E40F27FB23340744740

ซึ่งเมื่อใช้ฟังก์ชันST_AsEWKT(the_geom)จะคืนค่า:

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

ฉันต้องเลือกข้อมูลทั้งหมดที่อยู่ภายในรัศมี 30 กม. ของจุดละติจูด / ลองจิจูดเฉพาะเช่น:

  • lat = 46.8167
  • lng = 6.9333

อย่างไรก็ตามเมื่อใดก็ตามที่ฉันพยายามใช้ST_Distance()ฉันได้รับค่าน้อยกว่า 1 และใช้ST_DWithin()คืนจริงเสมอ

คำตอบ:


23

กรุณาตรวจสอบแบบสอบถามต่อไปนี้สำหรับ PostgreSQL เพื่อรับข้อมูลภายในระยะทางที่กำหนด ฉันหวังว่ามันจะช่วย

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

1
สามารถใช้งานได้กับ: เลือก * จาก myTable WHERE GeometryType (ST_Centroid (the_geom)) = 'POINT' และ ST_Distance_Sphere (ST_Point (ST_Centroid (the_geom)), ST_Y (ST_Centroid (the_geom)), 6.9M , 46.8167))) <= 18 * 1609.34
dan2k3k4

เยี่ยมมาก :)
Farhat Abbas

2
สำหรับคนอื่น ๆ ที่สงสัยว่าตัวเลข 1609.34 คือเมตรต่อไมล์ซึ่งเป็นหน่วยพื้นฐานที่ใช้ในขณะนี้ ดังนั้นในการทำกิโลเมตรคูณด้วย 1,000 เห็นได้ชัด
1mike12

2
โน้ตคนอวดรู้: มันคือ 1609.344 แน่นอน (ตามคำจำกัดความ)
barrycarter

6

ดูเหมือนว่าคุณกำลังจัดเก็บรูปทรงเรขาคณิตของคุณในคอลัมน์รูปทรงเรขาคณิตไม่ใช่คอลัมน์ทางภูมิศาสตร์
นั่นเป็นเรื่องปกติ แต่ฟังก์ชั่นST_D Distanceจะคืนค่าการวัดในหน่วยการฉายภาพแทนที่จะเป็นมาตรวัดเสมอ ในกรณีของคุณ (4326) นั่นจะเป็นองศา
เพียงแค่ใช้บัฟเฟอร์กับ ST_ ภายในจะไม่ทำงานเช่นกันเนื่องจากST_Bufferจะวัดด้วยองศาเช่นกัน

คุณสามารถแปลงข้อมูลของคุณเพื่อใช้ภูมิศาสตร์แทนที่จะเป็นรูปทรงเรขาคณิตหรือคุณสามารถแปลงจุดของคุณเป็นเส้นโครงที่ใช้หน่วยเมตรบัฟเฟอร์แล้วแปลงกลับเป็น 4326 เพื่อดูว่ามีอะไรอยู่ภายใน:

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

ที่ฉายจุดไปที่3857ซึ่งเป็นการฉายภาพยอดนิยมจากแผนที่เว็บ จากนั้นมันจะทำการบัฟเฟอร์ 30,000 เมตรจากนั้นจะทำการปฏิเสธมันกลับไปที่ 4326 ก่อนที่จะผ่านไปยัง ST_ ภายใน


ยกเว้น pseudo-Mercator ที่ไม่น่าเชื่อถือสำหรับระยะทางดังนั้นถ้าข้อมูลอยู่ใกล้กับเส้นศูนย์สูตรผลลัพธ์จะถูกปิดโดยเฉพาะอย่างยิ่งกับระยะทาง 30km
วินซ์

6

ในโลกของฉันใช้ SRID ที่กำหนดเอง (สำหรับ Google Maps) สิ่งนี้ทำงาน:

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

ที่ประเภทของการlocationเป็นรูปทรงเรขาคณิต (Point, 3785) และlongitude, latitudeและradiusมีลอย (เช่น -100, 44, 30 100W / 44N / 30 "หน่วย" - ดูด้านล่าง)

ดูวิธีที่ดีที่สุดในการค้นหาวัตถุทั้งหมดภายในรัศมีของวัตถุอื่นคืออะไร ในเอกสาร postgis:

ST_DWithin(geometry, geometry, distance)ฟังก์ชั่นเป็นวิธีที่สะดวกในการดำเนินการค้นหาระยะทางที่จัดทำดัชนี มันทำงานได้โดยการสร้างสี่เหลี่ยมการค้นหาที่มีขนาดใหญ่พอที่จะล้อมรัศมีระยะทางจากนั้นทำการค้นหาระยะทางที่แน่นอนในชุดย่อยของดัชนีที่มีการจัดทำดัชนี

การปรับปรุง: หน่วยไม่ใช่ไมล์สำหรับ SRID 3785 ... ดูเหมือนว่าจะเป็นเรเดียนหรือองศาหรืออะไรทำนองนั้น แต่สเปคสำหรับ SRID ของฉันบอกว่าหน่วยเป็นเมตรหรือองศาและแน่นอนว่ามันไม่ใช่ของอย่างน้อยก็ไม่มีการแปลงเลย:

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


3785 (ในโพสต์ของคุณ) แตกต่างกันอย่างไรกับ 3857
ปรับ

พวกเขากำลังฉายที่แตกต่างกัน 3875กับ3857 - ฉันไม่รู้ว่าอันไหนดีกว่ากัน
AlexChaffee

1
"EPSG 3785 เลิกใช้แล้วในความโปรดปรานของ EPSG 3857 ที่เหมือนกัน" - github.com/rgeo/rgeo/pull/61
Yarin

2

ฉันคิดว่าสิ่งนี้ควรใช้งานได้:

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

3
หากคุณส่งสัญญาณไปยังภูมิศาสตร์ที่ควรใช้งาน st_dwithin (ภูมิศาสตร์ (the_geom), ภูมิศาสตร์ (<จุด, 4326>), 30000)
cavila
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.