2011-10-04 23 views
14

मैं एक ओरेकल तालिका में डेटा डेटा करता हूं जो एक ग्राफ के रूप में व्यवस्थित होता है जिसमें चक्र हो सकते हैं (उदाहरण देखें)।गैर-पदानुक्रमित डेटा पर ओरेकल पदानुक्रमित क्वेरी

 CREATE TABLE T (parent INTEGER, child INTEGER) 
       AS select 1 parent, 2 child from dual 
     union all select 1 parent, 8 child from dual 
     union all select 2 parent, 3 child from dual 
     union all select 2 parent, 4 child from dual 
     union all select 2 parent, 8 child from dual 
     union all select 3 parent, 4 child from dual 
     union all select 3 parent, 6 child from dual 
     union all select 4 parent, 5 child from dual 
     union all select 5 parent, 8 child from dual 
     union all select 6 parent, 5 child from dual 
     union all select 7 parent, 3 child from dual 
     union all select 7 parent, 5 child from dual 
     union all select 8 parent, 6 child from dual 

Data sample

मेरा लक्ष्य सभी नोड्स उस नोड एक्स के वंशज (बच्चों, बच्चों के बच्चों, आदि) प्राप्त करने के लिए मान लीजिए कि 2 करते है। मेरे अपेक्षित परिणाम तो है: 3, 4, 5, 6, 8

मुझे पता है कि मैं इस तरह एक प्रश्न डिजाइन कर सकते हैं:

SELECT child, sys_connect_by_path(child,'/') 
    FROM T 
    START WITH parent = 2 
CONNECT BY NOCYCLE PRIOR child = PARENT; 

इस तरह के एक प्रश्न के साथ समस्या यह है इसके माध्यम से जाना होगा कि जब तक वे चक्र नहीं करते हैं, तब तक सभी संभावित पथ, और मेरे वास्तविक डेटा में उनमें से बहुत से तरीके हैं। परिणाम में कई डुप्लिकेट होते हैं - यहां यह है:

child | sys_connect_by_path (for information) 
3  | /3 
4  | /3/4 
5  | /3/4/5 
8  | /3/4/5/8 
6  | /3/4/5/8/6 
6  | /3/6 
5  | /3/6/5 
8  | /3/6/5/8 
4  | /4 
5  | /4/5 
8  | /4/5/8 
6  | /4/5/8/6 
8  | /8 
6  | /8/6 
5  | /8/6/5 

मेरा वास्तविक डेटा अधिक जटिल है। ऐसी क्वेरी के निष्पादन की लागत इतनी बड़ी है कि मेरा टीईएमपी टेबलस्पेस, जो ऑटोएक्स्टेंडेबल था, 10 जीबी (मूल रूप से 500 एमबी) तक पहुंच गया और मेरा डेटाबेस वास्तव में डिस्क पूर्ण होने के कारण टूट गया।

मैं इस तरह क्वेरी डिजाइन करने के लिए करने की कोशिश की (खंड के साथ पुनरावर्ती):

WITH descendants(node) AS 
(SELECT 2 node FROM dual 
    UNION ALL 
    (
    SELECT child 
    FROM T 
    INNER JOIN descendants D 
     ON T.parent = D.node 
    MINUS SELECT node FROM descendants 
) 
) 
SELECT * FROM descendants 

समस्या मैं का सामना है जो:

    Oracle 10g के साथ
  • , इस लागू नहीं है (ORA-32033: unsupported column aliasing, और कुछ ग्राहक ओरेकल 9 या 10 का उपयोग करते हैं),
  • ओरेकल 11 जी के साथ, मुझे ORA-32041: UNION ALL operation in recursive WITH clause must have only two branches मिलता है। यदि मैं MINUS क्लॉज को हटा देता हूं तो मुझे चक्र मिलेंगे (ORA-32044: cycle detected while executing recursive WITH query)।

उन नोड्स को 3, 4, 5, 6, 8 कुशलता से प्राप्त करने के लिए आप मेरे मूल डेटा से कैसे पूछेंगे? पीएल/एसक्यूएल समाधान भी स्वागत है।

धन्यवाद।

उत्तर

2

आपकी अपेक्षित अधिकतम गहराई किसी भी बच्चे नोड तक पहुंचने के लिए क्या है?

यह अपेक्षाकृत छोटा है, तो आप नीचे पाश कर सकते थे, जबकि इस तरह एक तरह से कुछ में नोड्स आप पहले से ही दौरा किया है के लिए जाँच, ...

(ध्यान दें, मैं नहीं एक Oracle विशेषज्ञ हूँ तो यह करीब है एक छोटे से वास्तविक) एसक्यूएल में मिश्रित

CREATE TABLE myMap (parent INT, child INT); 

INSERT INTO myTable SELECT NULL, 2 FROM DUAL; 

WHILE (SQL%ROWCOUNT > 0) 
LOOP 

    INSERT INTO 
    myMap 
    SELECT DISTINCT 
    dataMap.parent, 
    dataMap.child 
    FROM 
    myMap 
    INNER JOIN 
    dataMap 
     ON myMap.child = dataMap.parent 
    WHERE 
    NOT EXISTS (SELECT * FROM myMap WHERE parent = dataMap.parent) 

END LOOP; 

प्रदर्शन पर निर्भर करता है के साथ छद्म कोड के लिए, आप भी myMap में एक depth क्षेत्र चाहते हो सकता है; शामिल होने का अनुकूलन ताकि केवल हालिया नोड्स में शामिल हो सके। यह दो सूचकांक इंगित करेगा; जॉइन (depth) और एक EXISTS (parent) के लिए एक के लिए।

संपादित

जोड़ा गया DISTINCT महत्वपूर्ण शब्द है, तो निम्न मामले से बचने के लिए ...
- नोड 2 से 3 नक्शे और 4
- नोड्स 3 और 4 दोनों नक्शा 5
नोड के लिए - नोड 5 सभी बच्चों को अब दो बार

ग्रुप द्वारा, या कई अन्य विकल्पों संसाधित किया जाएगा, इस्तेमाल किया जा सकता DISTINCT के बजाय इसके लिए पूरा करने के लिए। यह सिर्फ इतना है कि अपने आप पर मौजूद नहीं है पर्याप्त नहीं है।

+0

यह अच्छा लग रहा है, धन्यवाद। क्या यह वैश्विक अस्थायी तालिका रखने का मामला है? – Benoit

+0

मैं नहीं चाहता कि तालिका वैश्विक हो। कल्पना कीजिए कि क्या हो सकता है अगर दो प्रक्रियाओं ने इसे एक साथ उपयोग करना शुरू किया? (यदि स्रोत तालिका को मध्य-निष्पादन में संशोधित किया गया है, तो यह पहले से ही 'असामान्य' व्यवहार के लिए खुला है। लेकिन अगर आपको आवश्यकता हो तो आप पूरी चीज को लेनदेन में सुरक्षित कर सकते हैं।) – MatBailie

+1

@Dems: जैसा कि आपने कहा था _global अस्थायी table_ के बारे में सिर्फ एक नोट ओरेकल विशेषज्ञ नहीं हैं। ओरेकल चीजों में अलग-अलग हैं: [ओरेकल में अस्थायी तालिका बनाम अस्थायी तालिका के बीच क्या अंतर है?] (Http://stackoverflow.com/q/417764) और [एक अस्थायी तालिका बनाना] (http: // डाउनलोड। oracle.com/docs/cd/E11882_01/server.112/e17120/tables003.htm#ADMIN11633) – user272735

1

मैंने इस के साथ काम नहीं किया है, लेकिन NOCYCLE विकल्प के साथ कनेक्ट के बारे में क्या? जब यह एक पाश देखता है तो पेड़ को तोड़ना बंद कर देना चाहिए। ओरेकल 11i निश्चित रूप से यह है कि, मुझे लगता है कि यह कहीं ओरेकल 10 जी अवधि में आया था।

+1

'आकर्षण से काम करता है 'एक आकर्षण की तरह काम करता है। उदाहरण यहां देखें: http://www.adp-gmbh.ch/ora/sql/connect_by_nocycle.html – michael667

+0

उत्तर देने के लिए धन्यवाद, लेकिन -1: मेरा प्रश्न दोबारा पढ़ें, मैं वर्तमान में कनेक्ट का उपयोग कर रहा हूं और यह अच्छी तरह से प्रदर्शन नहीं कर रहा है उस प्रकार के डेटा पर। – Benoit

+0

दाएं। मेरी त्रुटि माफ़ कीजिये। –

1

यह 4000 बाइट से अधिक होने तक यह मदद कर सकता है। चक्र संभव नहीं होना चाहिए लेकिन रेखा सिर्फ एक उदाहरण के रूप में है।

WITH descendants(node, lvl, pth, visited) AS 
    (
    SELECT child node, 1, cast(child as varchar2(4000)), '/'||listagg(child,'/') within group (order by child) over()||'/' 
     FROM t 
    where parent = 2 
    UNION ALL 
    SELECT child, lvl+1, pth||'/'||child, D.visited||listagg(child,'/') within group (order by child) over()||'/' 
     FROM T 
    INNER JOIN descendants D 
     ON T.parent = D.node 
    WHERE D.visited not like '%/'||child||'/%' 
    ) 
    cycle node set cyc to '1' default '0' 
    SELECT distinct node 
     FROM descendants 
    order by node 
    ; 
संबंधित मुद्दे