MySQL में पुनरावर्ती क्वेरी के साथ ट्री नोड से सभी वंशज कैसे प्राप्त करें?
यह वास्तव में MySql के लिए एक समस्या है, और यह इस प्रश्न का एक महत्वपूर्ण बिंदु है, लेकिन आपके पास अभी भी कुछ विकल्प हैं।
मान लें कि आपके पास ऐसा नमूना डेटा है, जितना आपके नमूने के रूप में नहीं बल्कि प्रदर्शित करने के लिए पर्याप्त है:
create table treeNode(
id int, parent_id int, name varchar(10), type varchar(10),level int);
insert into treeNode
(id, parent_id, name, type, level) values
( 1, 0, 'C1 ', 'CATEGORY', 1),
( 2, 1, 'C1.1 ', 'CATEGORY', 2),
( 3, 2, 'C1.1.1', 'CATEGORY', 3),
( 4, 1, 'C1.2 ', 'CATEGORY', 2),
( 5, 4, 'C1.2.1', 'CATEGORY', 3),
( 3, 8, 'G1.1.1', 'GROUP', 3),
( 4, 9, 'G1.2 ', 'GROUP', 2),
( 5, 4, 'G1.2.1', 'GROUP', 3),
( 8, 9, 'G1.1 ', 'GROUP', 2),
( 9, 0, 'G1 ', 'GROUP', 1);
पहली पसंद:लेवल कोड
ट्रीनोड तालिका में नाम कॉलम के नमूना डेटा की तरह। (मुझे नहीं पता कि इसे अंग्रेजी में कैसे कहें, level code
के सही एक्सप्रेशन के बारे में मुझे कमेंट करें ।)
C1
. के सभी वंशज प्राप्त करने के लिए या G1
इस तरह सरल हो सकता है:
select * from treeNode where type = 'CATEGORY' and name like 'C1%' ;
select * from treeNode where type = 'GROUP' and name like 'G1%' ;
मैं इस दृष्टिकोण को बहुत पसंद करता हूं, यहां तक कि हमें इन कोड को ट्रीनोड को एप्लिकेशन में सहेजे जाने से पहले उत्पन्न करने की आवश्यकता है। जब हमारे पास बड़ी संख्या में रिकॉर्ड होंगे तो यह पुनरावर्ती क्वेरी या प्रक्रिया से अधिक कुशल होगा। मुझे लगता है कि यह एक अच्छा डीनॉर्मलाइज़ेशन दृष्टिकोण है।
इस दृष्टिकोण के साथ, कथन आप शामिल होने के साथ want चाहते हैं हो सकता है:
SELECT distinct p.* --if there is only one tree node for a product, distinct is not needed
FROM product p
JOIN product_type pt
ON pt.id= p.parent_id -- to get product type of a product
JOIN linked_TreeNode LC
ON LC.product_id= p.id -- to get tree_nodes related to a product
JOIN (select * from treeNode where type = 'CATEGORY' and name like 'C1%' ) C --may replace C1% to concat('$selected_cat_name','%')
ON LC.treeNode_id = C.id
JOIN (select * from treeNode where type = 'GROUP' and name like 'G1%' ) G --may replace G1% to concat('$selected_group_name','%')
ON LC.treeNode_id = G.id
WHERE pt.name = '$selected_type' -- filter selected product type, assuming using product.name, if using product.parent_id, can save one join by pt like your original sql
मीठा, है ना?
दूसरा विकल्प:लेवल नंबर
डीडीएल में दिखाए गए अनुसार ट्रीनोड टेबल में एक लेवल कॉलम जोड़ें।
लेवल नंबर लेवल कोड . की तुलना में बनाए रखना बहुत आसान है आवेदन में।
C1
. के सभी वंशज प्राप्त करने के लिए स्तर संख्या के साथ या G1
इस तरह की एक छोटी सी तरकीब चाहिए:
SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids
FROM (select * from treeNode where type = 'CATEGORY' order by level) as t
JOIN (select @pv:='1')tmp
WHERE find_in_set(parent_id,@pv)
OR find_in_set(id,@pv);
-- get all descendants of `C1`
SELECT id, parent_id, name, type, @pv:=concat(@pv,',',id) as link_ids
FROM (select * from treeNode where type = 'GROUP' order by level) as t
JOIN (select @pv:=',9,')tmp
WHERE find_in_set(parent_id,@pv)
OR find_in_set(id,@pv) ;
यह दृष्टिकोण पहले की तुलना में धीमा है, लेकिन फिर भी पुनरावर्ती क्वेरी की तुलना में तेज़ है।
प्रश्न के लिए पूर्ण sql छोड़े गए। केवल उपरोक्त दो प्रश्नों के साथ C और G की उन दो उपश्रेणियों को बदलने की आवश्यकता है।
नोट:
कई समान दृष्टिकोण हैं जैसे यहां
, यहां
, या यहां तक कि यहां
. स्तर संख्या या स्तर कोड द्वारा आदेश दिए जाने तक वे काम नहीं करेंगे। आप इस SqlFiddle
में अंतिम क्वेरी का परीक्षण कर सकते हैं order by level
changing बदलकर करने के लिए order by id
अंतर देखने के लिए।
दूसरा विकल्प:नेस्टेड सेट मॉडल
कृपया इस ब्लॉग का संदर्भ लें , मैंने अभी तक परीक्षण नहीं किया है। लेकिन मुझे लगता है कि यह पिछली दो पसंद के समान है।
सभी वंशजों की आईडी को उनके बीच संलग्न करने के लिए आपको ट्रीनोड तालिका में एक बाएं नंबर और एक सही संख्या जोड़ने की आवश्यकता है।