आप लगभग वहाँ हैं। थोड़ी चाल है जो पोस्टग्रेज के अलग-अलग ऑपरेटर का उपयोग करना है , जो प्रत्येक संयोजन के पहले मैच को वापस कर देगा - जैसा कि आप ST_Distance द्वारा आदेश दे रहे हैं, प्रभावी रूप से यह प्रत्येक बंदरगाह से प्रत्येक सेनल से निकटतम बिंदु वापस आ जाएगा।
SELECT
DISTINCT ON (senal.id) senal.id, port.id, ST_Distance(port."GEOMETRY", senal."GEOMETRY") as dist
FROM traffic_signs As senal, entrance_halls As port
ORDER BY senal.id, port.id, ST_Distance(port."GEOMETRY", senal."GEOMETRY");
यदि आप जानते हैं कि प्रत्येक मामले में न्यूनतम दूरी कुछ राशि x से अधिक नहीं है, (और आपकी तालिकाओं पर एक स्थानिक सूचकांक है), तो आप इसको गति प्रदान कर सकते हैं WHERE ST_DWithin(port."GEOMETRY", senal."GEOMETRY", distance)
, जैसे, यदि सभी ऋण दूरी ज्ञात की जाती हैं 10 किमी से अधिक नहीं, फिर:
SELECT
DISTINCT ON (senal.id) senal.id, port.id, ST_Distance(port."GEOMETRY", senal."GEOMETRY") as dist
FROM traffic_signs As senal, entrance_halls As port
WHERE ST_DWithin(port."GEOMETRY", senal."GEOMETRY", 10000)
ORDER BY senal.id, port.id, ST_Distance(port."GEOMETRY", senal."GEOMETRY");
जाहिर है, इसे सावधानी के साथ उपयोग करने की आवश्यकता है, जैसे कि न्यूनतम दूरी अधिक होने पर, आपको बस सीनल और पोर्ट के संयोजन के लिए कोई पंक्ति नहीं मिलेगी।
नोट: ऑर्डर द्वारा ऑर्डर ऑर्डर पर अलग से मेल खाना चाहिए, जो समझ में आता है, क्योंकि अलग-अलग कुछ ऑर्डर करने के आधार पर अलग-अलग पहला समूह ले रहा है।
यह माना जाता है कि आपके पास दोनों तालिकाओं पर एक स्थानिक सूचकांक है।
EDIT 1 । एक और विकल्प है, जो Postgres के <-> और <#> ऑपरेटरों का उपयोग करना है, (केंद्र बिंदु और क्रमशः बॉक्स दूरी की गणना,) जो स्थानिक सूचकांक का अधिक कुशल उपयोग करते हैं और n से बचने के लिए ST_DWithin हैक की आवश्यकता नहीं होती है ^ 2 तुलना। एक अच्छा ब्लॉग लेख है जो बताता है कि वे कैसे काम करते हैं। सामान्य बात यह है कि ये दोनों ऑपरेटर ORDER BY क्लॉज में काम करते हैं।
SELECT senal.id,
(SELECT port.id
FROM entrance_halls as port
ORDER BY senal.geom <#> port.geom LIMIT 1)
FROM traffic_signs as senal;
EDIT 2 । जैसा कि इस सवाल पर बहुत अधिक ध्यान दिया गया है और के-निकटतम पड़ोसियों (केएनएन) जीआईएस में आम तौर पर एक कठिन समस्या है (एल्गोरिदमिक रन-टाइम के संदर्भ में), इस प्रश्न के मूल दायरे पर कुछ हद तक विस्तार करना सार्थक लगता है।
एक वस्तु के x निकटतम पड़ोसियों को खोजने का मानक तरीका एक लोट्टल जॉयइन (प्रत्येक लूप के लिए वैचारिक रूप से समान) का उपयोग करना है। डबस्टन के जवाब से बेशर्मी से बोलना , आप कुछ ऐसा करेंगे:
SELECT
signs.id,
closest_port.id,
closest_port.dist
FROM traffic_signs
CROSS JOIN LATERAL
(SELECT
id,
ST_Distance(ports.geom, signs.geom) as dist
FROM ports
ORDER BY signs.geom <-> ports.geom
LIMIT 1
) AS closest_port
इसलिए, यदि आप दूरी द्वारा आदेश दिए गए निकटतम 10 बंदरगाहों को खोजना चाहते हैं, तो आपको बस पार्श्व उप-क्वेरी में लिमिट क्लॉज को बदलना होगा। LATERAL JOINS के बिना ऐसा करना बहुत कठिन है और इसमें ARRAY प्रकार के तर्क का उपयोग करना शामिल है। जबकि यह दृष्टिकोण अच्छी तरह से काम करता है, इसे काफी हद तक फैलाया जा सकता है यदि आप जानते हैं कि आपको केवल एक निश्चित दूरी पर खोज करना है। इस उदाहरण में, आप ST_DWithin (signs.geom, ports.geom, 1000) का उपयोग उपकुंजी में कर सकते हैं , क्योंकि जिस तरह से इंडेक्सिंग <-> ऑपरेटर के साथ काम करता है - एक ज्यामितीय का एक स्थिर होना चाहिए, बजाय स्तंभ संदर्भ - बहुत तेज हो सकता है। इसलिए, उदाहरण के लिए, 10 किमी के भीतर 3 निकटतम बंदरगाहों को प्राप्त करने के लिए, आप निम्नलिखित की तरह कुछ लिख सकते हैं।
SELECT
signs.id,
closest_port.id,
closest_port.dist
FROM traffic_signs
CROSS JOIN LATERAL
(SELECT
id,
ST_Distance(ports.geom, signs.geom) as dist
FROM ports
WHERE ST_DWithin(ports.geom, signs.geom, 10000)
ORDER BY ST_Distance(ports.geom, signs.geom)
LIMIT 3
) AS closest_port;
हमेशा की तरह, उपयोग आपके डेटा वितरण और प्रश्नों के आधार पर अलग-अलग होगा, इसलिए EXPLAIN आपका सबसे अच्छा दोस्त है।
अंत में, एक छोटी सी पकड़ लिया है, का उपयोग कर यदि वाम के बजाय क्रॉस पार्श्व में शामिल हों आप जोड़ने के लिए है कि सच पार्श्व प्रश्नों उर्फ के बाद, जैसे,
SELECT
signs.id,
closest_port.id,
closest_port.dist
FROM traffic_signs
LEFT JOIN LATERAL
(SELECT
id,
ST_Distance(ports.geom, signs.geom) as dist
FROM ports
ORDER BY signs.geom <-> ports.geom
LIMIT 1
) AS closest_port
ON TRUE;