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

एक क्लोजर टेबल पदानुक्रमित-डेटा संरचना में एक सबट्री को सॉर्ट करना

यह प्रश्न न केवल क्लोजर टेबल के लिए बल्कि पदानुक्रमित डेटा संग्रहीत करने के अन्य तरीकों के लिए भी बार-बार आता है। किसी भी डिज़ाइन में यह आसान नहीं है।

क्लोजर टेबल के लिए मैंने जो समाधान निकाला है, उसमें एक अतिरिक्त जुड़ाव शामिल है। पेड़ में प्रत्येक नोड अपने पूर्वजों की श्रृंखला से जुड़ता है, जैसे "ब्रेडक्रंब" प्रकार की क्वेरी। फिर ब्रेडक्रंब को अल्पविराम से अलग स्ट्रिंग में संक्षिप्त करने के लिए GROUP_CONCAT() का उपयोग करें, आईडी संख्याओं को पेड़ में गहराई से क्रमबद्ध करें। अब आपके पास एक स्ट्रिंग है जिसके द्वारा आप सॉर्ट कर सकते हैं।

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(breadcrumb.ancestor ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,3         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,3,4       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,3,7       |
|  6 | Cat 1.2    |      1 |       1 | 1,6         |
+----+------------+--------+---------+-------------+

चेतावनी:

  • आईडी मानों की लंबाई एक समान होनी चाहिए, क्योंकि "1,3" और "1,6" और "1,327" को छांटने से वह क्रम नहीं मिल सकता है जो आप चाहते हैं। लेकिन "001,003" और "001,006" और "001,327" को छांटना होगा। तो आपको या तो अपना आईडी मान 1000000+ से शुरू करना होगा, या फिर ZEROFILL का उपयोग करना होगा श्रेणी_बंद तालिका में पूर्वजों और वंशजों के लिए।
  • इस समाधान में प्रदर्शन क्रम श्रेणी आईडी के संख्यात्मक क्रम पर निर्भर करता है। आईडी मानों का वह संख्यात्मक क्रम उस क्रम का प्रतिनिधित्व नहीं कर सकता है जिसे आप पेड़ प्रदर्शित करना चाहते हैं। या आप संख्यात्मक आईडी मानों के बावजूद प्रदर्शन क्रम को बदलने की स्वतंत्रता चाहते हैं। या हो सकता है कि आप एक ही श्रेणी के डेटा को एक से अधिक ट्री में दिखाना चाहते हों, प्रत्येक में अलग-अलग डिस्प्ले ऑर्डर हों।
    यदि आपको अधिक स्वतंत्रता की आवश्यकता है, तो आपको आईडी से अलग सॉर्ट-ऑर्डर मानों को स्टोर करने की आवश्यकता है, और समाधान हो जाता है और भी जटिल। लेकिन अधिकांश प्रोजेक्ट्स में, शॉर्ट-कट का उपयोग करना स्वीकार्य है, जिससे श्रेणी आईडी का डबल-ड्यूटी ट्री डिस्प्ले ऑर्डर के रूप में दिया जाता है।

अपनी टिप्पणी दें:

हां, आप क्लोजर टेबल में "सिब्लिंग सॉर्ट ऑर्डर" को दूसरे कॉलम के रूप में स्टोर कर सकते हैं, फिर ancestor के बजाय उस मान का उपयोग करें ब्रेडक्रंब स्ट्रिंग बनाने के लिए। लेकिन अगर आप ऐसा करते हैं, तो आप बहुत अधिक डेटा अतिरेक के साथ समाप्त हो जाते हैं। यही है, किसी दिए गए पूर्वज को कई पंक्तियों में संग्रहीत किया जाता है, प्रत्येक पथ से नीचे आने के लिए एक। तो आपको उन सभी पंक्तियों पर सिबलिंग सॉर्ट ऑर्डर के लिए समान मान संग्रहीत करना होगा, जो एक विसंगति का जोखिम पैदा करता है।

विकल्प यह होगा कि केवल एक . के साथ एक और तालिका बनाई जाए पेड़ में प्रति विशिष्ट पूर्वज पंक्ति, और भाई-बहन आदेश प्राप्त करने के लिए उस तालिका में शामिल हों।

CREATE TABLE category_closure_order (
  ancestor INT PRIMARY KEY,
  sibling_order SMALLINT UNSIGNED NOT NULL DEFAULT 1
);

SELECT c2.*, cc2.ancestor AS `_parent`,
  GROUP_CONCAT(o.sibling_order ORDER BY breadcrumb.depth DESC) AS breadcrumbs
FROM category AS c1
JOIN category_closure AS cc1 ON (cc1.ancestor = c1.id)
JOIN category AS c2 ON (cc1.descendant = c2.id)
LEFT OUTER JOIN category_closure AS cc2 ON (cc2.descendant = c2.id AND cc2.depth = 1)
JOIN category_closure AS breadcrumb ON (cc1.descendant = breadcrumb.descendant)
JOIN category_closure_order AS o ON breadcrumb.ancestor = o.ancestor
WHERE c1.id = 1/*__ROOT__*/ AND c1.active = 1
GROUP BY cc1.descendant
ORDER BY breadcrumbs;

+----+------------+--------+---------+-------------+
| id | name       | active | _parent | breadcrumbs |
+----+------------+--------+---------+-------------+
|  1 | Cat 1      |      1 |    NULL | 1           |
|  3 | Cat  1.1   |      1 |       1 | 1,1         |
|  4 | Cat  1.1.1 |      1 |       3 | 1,1,1       |
|  7 | Cat 1.1.2  |      1 |       3 | 1,1,2       |
|  6 | Cat 1.2    |      1 |       1 | 1,2         |
+----+------------+--------+---------+-------------+



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. utf-8 बनाम latin1

  2. सभी तिथियों के बीच दिखाएं, भले ही कोई परिणाम न हो

  3. पर्ल में रेंगने के दौरान MySQL सर्वर चला गया है

  4. Mysql में एक सेल का डेटा बदलें

  5. PHP सरल HTML डोम पार्सर के साथ कैरेक्टर एन्कोडिंग समस्या