আপনি প্রায় সেখানে আছেন। পোস্টগ্রিসের স্বতন্ত্র অপারেটরটি ব্যবহার করার জন্য একটি ছোট কৌশল রয়েছে যা প্রতিটি সংমিশ্রনের প্রথম ম্যাচটি ফিরিয়ে দেবে - আপনি যেমন 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)
যদি সমস্ত ন্যূনতম দূরত্ব বলে জানা যায় তবে আপনি এটি বাড়িয়ে দিতে পারেন eg 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");
স্পষ্টতই, এটি সতর্কতার সাথে ব্যবহার করা দরকার, যেন ন্যূনতম দূরত্ব বেশি হয় তবে আপনি কেবল সেনাল এবং বন্দরের সংমিশ্রনের জন্য কোনও সারি পাবেন না।
দ্রষ্টব্য: আদেশ অনুসারে ক্রমটি অবশ্যই অর্ডের সাথে স্বতন্ত্রের সাথে মিলবে, যা বোঝা যায়, কারণ কিছু আদেশের ভিত্তিতে স্বতন্ত্র প্রথম স্বতন্ত্র গ্রুপটি গ্রহণ করে।
ধারণা করা হয় যে উভয় টেবিলে আপনার স্থানিক সূচক রয়েছে।
সম্পাদনা 1 । আরেকটি বিকল্প রয়েছে, যা পোস্টগ্রিসের <-> এবং <#> অপারেটরগুলি (যথাক্রমে সেন্টার পয়েন্ট এবং বাউন্ডিং বক্সের দূরত্ব গণনা) ব্যবহার করা হয় যা স্থানিক সূচকের আরও দক্ষ ব্যবহার করে এবং এন এড়ানোর জন্য এসT_ডুইথিন হ্যাকের প্রয়োজন হয় না । 2 তুলনা। তারা কীভাবে কাজ করে তা বোঝানোর জন্য একটি ভাল ব্লগ নিবন্ধ রয়েছে । সাধারণ বিষয় লক্ষণীয় যে এই দুটি অপারেটর অর্ডার বাই ক্লজে কাজ করে।
SELECT senal.id,
(SELECT port.id
FROM entrance_halls as port
ORDER BY senal.geom <#> port.geom LIMIT 1)
FROM traffic_signs as senal;
সম্পাদনা 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 টি বন্দরগুলি সন্ধান করতে চান তবে আপনাকে কেবল পাশের সাব-কোয়েরিতে LIMIT টি ধারা পরিবর্তন করতে হবে। ল্যাটারাল জয়েনগুলি ছাড়া এটি করা খুব শক্ত এবং এআরএআর টাইপের যুক্তি ব্যবহারের সাথে জড়িত। এই পদ্ধতিরটি ভালভাবে কাজ করার সময়, এটি যদি আপনি জানেন তবে আপনাকে কেবল একটি নির্দিষ্ট দূরত্বে সন্ধান করতে হবে তবে তা প্রচুর পরিমাণে বাড়ানো যেতে পারে। এই উদাহরণস্বরূপ, আপনি উপকোয়ায় ST_DWithin (চিহ্ন.জম, পোর্টস.জম, 1000) ব্যবহার করতে পারেন , যেহেতু <-> অপারেটরের সাথে ইনডেক্সিং কাজ করে - কারণ জ্যামিতির একটি স্থির হওয়া উচিত কলাম রেফারেন্স - অনেক দ্রুত হতে পারে। সুতরাং, উদাহরণস্বরূপ, 3 নিকটতম বন্দর পেতে, 10 কিলোমিটারের মধ্যে, আপনি নীচের মতো কিছু লিখতে পারেন।
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;
সর্বদা হিসাবে, ব্যবহার আপনার ডেটা বিতরণ এবং ক্যোয়ারির উপর নির্ভর করে পরিবর্তিত হবে, সুতরাং আপনার সেরা বন্ধু হিসাবে ব্যাখ্যা করুন ।
অবশেষে, একটি ছোটখাটো গ্যাচা রয়েছে, যদি পাশের ক্রস লেটারেলের পরিবর্তে বাম ব্যবহার করা হয় তবে আপনাকে পাশ্ববর্তী ক্যোয়ারী নামগুলির পরে সত্য যুক্ত করতে হবে , উদাহরণস্বরূপ,
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;