PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

दो तालिकाओं के बीच निकटतम बिंदुओं का अद्वितीय असाइनमेंट

टेबल स्कीमा

अपना नियम लागू करने के लिए बस pvanlagen.buildid . घोषित करें UNIQUE :

ALTER TABLE pvanlagen ADD CONSTRAINT pvanlagen_buildid_uni UNIQUE (buildid);

build.gid पीके है, जैसा कि आपके अपडेट से पता चला है। संदर्भात्मक अखंडता को भी लागू करने के लिए एक विदेशी कुंजी बाधा करने के लिए बिल्डिंग.gid

आपने अब तक दोनों को लागू कर दिया है। लेकिन बड़े UPDATE को चलाना अधिक कुशल होगा नीचे पहले आप इन बाधाओं को जोड़ते हैं।

आपकी तालिका परिभाषा में और भी बहुत कुछ सुधार किया जाना चाहिए। एक के लिए, builds.gid साथ ही pvanlagen.buildid पूर्णांक type प्रकार का होना चाहिए (या संभवतः बिगिन्ट अगर आप बहुत जलाते हैं पीके मूल्यों के)। संख्यात्मक महंगा बकवास है।

आइए मुख्य समस्या पर ध्यान दें:

निकटतम भवन खोजने के लिए मूल प्रश्न

मामला इतना आसान नहीं है जितना लग रहा है। यह एक "निकटतम पड़ोसी" समस्या, अद्वितीय असाइनमेंट की अतिरिक्त जटिलता के साथ।

यह क्वेरी निकटतम एक . ढूंढती है प्रत्येक PV के लिए भवन (PV Anlage के लिए संक्षिप्त - pvanlagen . में पंक्ति) ), जहां न तो असाइन किया गया है, फिर भी:

SELECT pv_gid, b_gid, dist
FROM  (
   SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
   FROM   pvanlagen
   WHERE  buildid IS NULL  -- not assigned yet
   ) p
     , LATERAL (
   SELECT b.gid AS b_gid
        , round(ST_Distance(p.geom31467
                      , ST_Transform(b.centroid, 31467))::numeric, 2) AS dist  -- see below
   FROM   buildings b
   LEFT   JOIN pvanlagen p1 ON p1.buildid = b.gid  -- also not assigned ...
   WHERE  p1.buildid IS NULL                       -- ... yet  
   -- AND    p.gemname = b.gemname                 -- not needed for performance, see below
   ORDER  BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
   LIMIT  1
   ) b;

इस क्वेरी को तेज़ बनाने के लिए, आपको जरूरत इमारतों . पर एक स्थानिक, कार्यात्मक जिस्ट इंडेक्स इसे काफी बनाने के लिए तेज़:

CREATE INDEX build_centroid_gix ON buildings USING gist (ST_Transform(centroid, 31467));

यकीन नहीं होता क्यों आप नहीं

अधिक स्पष्टीकरण के साथ संबंधित उत्तर:

आगे पढ़ना:

अनुक्रमणिका के साथ, हमें मिलानों को उसी रत्न नाम . तक सीमित करने की आवश्यकता नहीं है प्रदर्शन के लिए। ऐसा केवल तभी करें जब इसे लागू करने का एक वास्तविक नियम हो। यदि इसे हर समय देखा जाना है, तो कॉलम को FK बाधा में शामिल करें:

शेष समस्या

हम उपरोक्त क्वेरी का उपयोग UPDATE . में कर सकते हैं बयान। प्रत्येक PV का उपयोग केवल एक बार किया जाता है, लेकिन एक से अधिक PV को अभी भी एक ही भवन मिल सकता है निकटतम होना। आप केवल एक की अनुमति देते हैं प्रति भवन पी.वी. तो आप इसका समाधान कैसे करेंगे?

दूसरे शब्दों में, आप यहाँ वस्तुओं को कैसे निर्दिष्ट करेंगे?

सरल समाधान

एक आसान उपाय होगा:

UPDATE pvanlagen p1
SET    buildid = sub.b_gid
     , dist    = sub.dist  -- actual distance
FROM  (
   SELECT DISTINCT ON (b_gid)
          pv_gid, b_gid, dist
   FROM  (
      SELECT gid AS pv_gid, ST_Transform(geom, 31467) AS geom31467
      FROM   pvanlagen
      WHERE  buildid IS NULL  -- not assigned yet
      ) p
        , LATERAL (
      SELECT b.gid AS b_gid
           , round(ST_Distance(p.geom31467
                         , ST_Transform(b.centroid, 31467))::numeric, 2) AS dist  -- see below
      FROM   buildings      b
      LEFT   JOIN pvanlagen p1 ON p1.buildid = b.gid  -- also not assigned ...
      WHERE  p1.buildid IS NULL                       -- ... yet  
      -- AND    p.gemname = b.gemname                 -- not needed for performance, see below
      ORDER  BY p.geom31467 <-> ST_Transform(b.centroid, 31467)
      LIMIT  1
      ) b
   ORDER  BY b_gid, dist, pv_gid  -- tie breaker
   ) sub
WHERE   p1.gid = sub.pv_gid;

मैं DISTINCT ON (b_gid) . का उपयोग करता हूं बिल्कुल एक . को कम करने के लिए प्रति भवन पंक्ति, कम से कम दूरी के साथ पीवी चुनना। विवरण:

किसी भी भवन के लिए जो एक से अधिक PV के निकटतम है, केवल निकटतम PV असाइन किया गया है। PK कॉलम gid (उपनाम pv_gid ) टाईब्रेकर के रूप में कार्य करता है यदि दो समान रूप से निकट हों। ऐसी स्थिति में, कुछ PV अपडेट से हटा दिए जाते हैं और असाइन किए गए . रहते हैं . दोहराएं जब तक सभी पीवी असाइन नहीं हो जाते तब तक क्वेरी करें।

यह अभी भी एक सरल एल्गोरिथम है , यद्यपि। ऊपर दिए गए मेरे आरेख को देखते हुए, यह 4 से PV 4 और बिल्डिंग 5 से PV 5 को असाइन करता है, जबकि 4-5 और 5-4 शायद समग्र रूप से एक बेहतर समाधान होगा ...

इसके अलावा:dist के लिए टाइप करें कॉलम

वर्तमान में आप numeric इसके लिए। आपकी मूल क्वेरी ने एक स्थिर पूर्णांक असाइन किया है , संख्यात्मक में कोई मतलब नहीं है ।

मेरी नई क्वेरी में ST_Distance() मीटर में वास्तविक दूरी को double के रूप में लौटाता है सटीक . यदि हम केवल यह निर्दिष्ट करते हैं कि हमें संख्यात्मक . में 15 या इतने ही भिन्नात्मक अंक प्राप्त होते हैं डेटा प्रकार, और संख्या वह नहीं है शुरू करने के लिए सटीक। मुझे गंभीरता से संदेह है कि आप संग्रहण को बर्बाद करना चाहते हैं।

इसके बजाय मैं मूल दोहरी सटीकता को सहेजना चाहूंगा गणना से। या, अभी तक बेहतर , आवश्यकतानुसार गोल। यदि मीटर काफी सटीक हैं, तो बस एक पूर्णांक . पर कास्ट करें और सहेजें (संख्या को स्वचालित रूप से गोल करना)। या सेमी को बचाने के लिए पहले 100 से गुणा करें:

(ST_Distance(...) * 100)::int



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL को क्लाउड में माइग्रेट करना - Amazon, Google और Microsoft से समाधानों की तुलना करना

  2. पांडा में इष्टतम खंड आकार पैरामीटर।DataFrame.to_sql

  3. रिफैक्टर कार्य करता है ताकि उनका उपयोग सीटीई के भीतर किया जा सके

  4. PostgreSQL में विभिन्न स्कैन विधियों का अवलोकन

  5. समय क्षेत्र समानता के साथ समय को पोस्टग्रेज करता है