2008-09-09 23 views
62

मेरे पास एक सारणी है:क्या रिकर्सिव एसक्यूएल क्वेरी बनाना संभव है?

CREATE TABLE example (
    id integer primary key, 
    name char(200), 
    parentid integer, 
    value integer); 

मैं पेड़ संरचना में डेटा व्यवस्थित करने के लिए पैरेंट फ़ील्ड का उपयोग कर सकता हूं।

अब यहां थोड़ा सा काम नहीं कर सकता है। अभिभावक को देखते हुए, क्या उस अभिभावक के तहत सभी मूल्य फ़ील्ड जोड़ने और पेड़ की शाखा को पुन: स्थापित करने के लिए SQL कथन लिखना संभव है?

अद्यतन: मैं posgreSQL का उपयोग कर रहा हूं इसलिए फैंसी एमएस-एसक्यूएल विशेषताएं मेरे लिए उपलब्ध नहीं हैं। किसी भी मामले में, मैं इसे एक सामान्य SQL प्रश्न के रूप में माना जाना चाहूंगा।

बीटीडब्लू, मैं सवाल पूछने के 15 मिनट के भीतर 6 उत्तरों के लिए बहुत प्रभावित हूं! ढेर अतिप्रवाह जाओ!

+3

यह हेरार्किकल डेटा है। मुझे एसक्यूएल कुकबुक (O'Reilly) में विरासत डेटा पर एंथनी मोलिनेरो की चर्चा वास्तव में आसान होने के लिए मिली है; वह PostrgreSQL सहित लगभग सभी लोकप्रिय डीबीएमएस को कवर करता है। –

+0

मैं posgreSQL का उपयोग कर रहा हूं इसलिए फैंसी एमएस-एसक्यूएल विशेषताएं मेरे लिए उपलब्ध नहीं हैं। किसी भी मामले में, मैं इसे एक सामान्य SQL प्रश्न के रूप में माना जाना चाहूंगा। बीटीडब्लू, मैं सवाल पूछने के 15 मिनट के भीतर 6 उत्तरों के लिए बहुत प्रभावित हूं! ढेर अतिप्रवाह जाओ! –

+1

यदि आप यहां Google चेक @Chris KL प्रतिक्रिया से आते हैं, क्योंकि PostgreSQl 8.4 रिकर्सिव क्वेरी postgreSQL पर उपलब्ध हैं। – regilero

उत्तर

11

PostgreSQL में आपको जो चाहिए वह करने के कुछ तरीके हैं।

  • यदि आप मॉड्यूल स्थापित कर सकते हैं, तो tablefunc contrib देखें। इसमें एक कनेक्टबी() फ़ंक्शन है जो पेड़ को पार करने वाले हैंडल करता है। http://www.postgresql.org/docs/8.3/interactive/tablefunc.html

  • इसके अलावा ltree योगदान है, जो आप का उपयोग करने के अपने टेबल खुद को अनुकूलित कर बाहर की जाँच: http://www.postgresql.org/docs/8.3/interactive/ltree.html

  • या आप पेड़ अपने आप को एक PL/pgSQL समारोह के साथ पार कर सकते हैं।

कुछ इस तरह:

create or replace function example_subtree (integer) 
returns setof example as 
'declare results record; 
     child record; 
begin 
    select into results * from example where parent_id = $1; 
    if found then 
    return next results; 
    for child in select id from example 
        where parent_id = $1 
     loop 
     for temp in select * from example_subtree(child.id) 
     loop 
      return next temp; 
     end loop; 
     end loop; 
    end if; 
    return null; 
end;' language 'plpgsql'; 

select sum(value) as value_sum 
    from example_subtree(1234); 
0

यह SQL सर्वर है? क्या आप एक टीएसक्यूएल संग्रहीत प्रक्रिया नहीं लिख सकते हैं जो परिणामों को एक साथ लूप करता है और यूनियनों को एक साथ जोड़ता है?

मुझे यह भी रुचि है कि ऐसा करने का एकमात्र तरीका है। बिट्स से मुझे अपने भौगोलिक डेटाबेस वर्ग से याद है, वहां होना चाहिए।

5

common table expression का उपयोग करें।

मई यह इंगित करना चाहता है कि यह केवल SQL Server 2005 या ऊपर है। Dale Ragan

आम तालिका भाव के बिना SqlTeam द्वारा प्रत्यावर्तन पर here's an article

+0

मई यह इंगित करना चाहता है कि यह केवल SQL Server 2005 या ऊपर है। –

+0

अब इसे देखकर महसूस न करें, लेकिन मुझे पता है कि ऑरैकल 10 जी क्लॉज के साथ है, मुझे आश्चर्य है कि यह भी संभव है। –

+1

ओरेकल 11 जीआर 2 ने क्लॉज के साथ रिकर्सिव के लिए समर्थन प्रस्तुत किया; इससे पहले कि एक खंड के साथ खुद को संदर्भित नहीं किया जा सका। पूर्व संस्करणों के लिए, ओरेकल के पास पहले से ही कम से कम संस्करण 7 या 8 के बाद से अपने स्वयं के पदानुक्रमित क्वेरी सिंटैक्स (स्टार्ट के साथ + कनेक्ट करें) था। –

0

मुझे लगता है कि यह HierarchyID

+0

सहमत हुए। डेटाबेस बाध्य मेनू बहुत अच्छी तरह से होने जा रहे हैं। –

5

साथ एसक्यूएल 2008 में आसान है अपने का उपयोग कर SQL सर्वर 2005, इस का उपयोग करते हुए आम टेबल भाव करने के लिए एक बहुत अच्छा तरीका है।

यह एक अस्थायी तालिका बनाने से बाहर निकलता है, और मूल रूप से आप इसे केवल एक और एक यूनियन के साथ करने की अनुमति देता है।

http://searchwindevelopment.techtarget.com/tip/0,289483,sid8_gci1278207,00.html

15

आप एक पोर्टेबल समाधान चाहते हैं कि "होगा कनेक्ट":

यहाँ एक अच्छा ट्यूटोरियल है किसी भी एएनएसआई SQL-92 आरडीबीएमएस पर काम करें, आपको अपनी तालिका में एक नया कॉलम जोड़ना होगा।

जो सेल्को Nested Sets एसक्यूएल में पदानुक्रमों को संग्रहित करने के लिए दृष्टिकोण का मूल लेखक है। पृष्ठभूमि के बारे में अधिक जानने के लिए आप Google "nested sets" hierarchy कर सकते हैं।

या आप बस नाम बदल सकते हैं parentid को leftid और जोड़ने के एक rightid

नेस्टेड सेट्स को सारांशित करने का मेरा प्रयास यहां दिया गया है, जो बहुत कम हो जाएगा क्योंकि मैं कोई जोल्को नहीं हूं: एसक्यूएल एक सेट-आधारित भाषा है, और आसन्न मॉडल (अभिभावक आईडी भंडारण) सेट-आधारित प्रतिनिधित्व नहीं है पदानुक्रम का। इसलिए आसन्नता स्कीमा पूछने के लिए कोई शुद्ध सेट-आधारित विधि नहीं है।

हालांकि, अधिकांश प्रमुख प्लेटफॉर्म ने इस सटीक समस्या से निपटने के लिए हाल के वर्षों में एक्सटेंशन पेश किए हैं। तो अगर कोई पोस्टग्रेस-विशिष्ट समाधान के साथ जवाब देता है, तो इसका हर तरह से उपयोग करें।

+0

सेल्को को एक बुरा प्रतिनिधि लगता है, लेकिन वह अभी भी आदमी है –

+0

@ पोर्टमैन मैंने नेस्टेड सेट को देखा है। एक अच्छा विचार लगता है, लेकिन ऐसा लगता है कि डालने/हटाने की लागत बहुत अधिक है। – Kibbee

+0

हां, * लगता है *। लेकिन मेरा विश्वास करो - एक बार जब आप सीआरयूडी प्रक्रियाओं को लिखते हैं, तो यह बहुत अच्छा प्रदर्शन करता है। – Portman

-1

आप मनमाने ढंग से रेखांकन स्टोर करने के लिए की जरूरत है, न कि केवल पदानुक्रम, आप Postgres ओर करने के लिए धक्का है और इस तरह के रूप में एक AllegroGraph ग्राफ डेटाबेस की कोशिश कर सकते:

ग्राफ डेटाबेस में सब कुछ एक ट्रिपल (स्रोत नोड के रूप में संग्रहीत किया जाता है, किनारे, लक्ष्य नोड) और यह आपको ग्राफ़ संरचना में हेरफेर करने और भाषा जैसे एसक्यूएल का उपयोग करके पूछताछ के लिए प्रथम श्रेणी का समर्थन देता है।

यह हाइबरनेट या डैंजो ओआरएम जैसे कुछ के साथ अच्छी तरह से एकीकृत नहीं है, लेकिन यदि आप ग्राफ संरचनाओं के बारे में गंभीर हैं (न केवल नेस्टेड सेट मॉडल की पदानुक्रम आपको देता है) इसे जांचें।

मुझे यह भी विश्वास है कि ओरेकल ने अंततः अपने नवीनतम उत्पादों में वास्तविक ग्राफ के लिए एक समर्थन जोड़ा है, लेकिन मुझे आश्चर्य है कि यह इतना लंबा लिया गया है, इस मॉडल से कई समस्याएं लाभान्वित हो सकती हैं।

+0

उत्सुक क्यों डाउनवोट - एलेग्राग्राफ के लिए विशिष्ट समस्या? सामान्य रूप से ग्राफ डेटाबेस के बारे में एक चिंता? रिकर्सिव क्वेरी को निष्पादित करने के तरीके पर स्पष्ट रूप से स्पर्श नहीं करना चाहिए? – dat

2

निम्न कोड को संकलित करता है और यह ठीक परीक्षण किया है।

 
create or replace function subtree (bigint) 
returns setof example as $$ 
declare 
    results record; 
    entry record; 
    recs record; 
begin 
    select into results * from example where parent = $1; 
    if found then 
     for entry in select child from example where parent = $1 and child parent loop 
      for recs in select * from subtree(entry.child) loop 
       return next recs; 
      end loop; 
     end loop; 
    end if; 
    return next results; 
end; 
$$ language 'plpgsql'; 

हालत "बच्चे <> जनक" मेरे मामले में की जरूरत है क्योंकि नोड्स स्वयं का संकेत।

मज़े :)

34

संस्करण 8.4 के बाद से, PostgreSQL एसक्यूएल मानक WITH सिंटैक्स का उपयोग आम तालिका अभिव्यक्ति के लिए recursive query support है।

1

बस के रूप में एक संक्षिप्त एक तरफ हालांकि सवाल बहुत अच्छी तरह से जवाब दिया गया है, यह ध्यान दिया जाना चाहिए कि अगर हम एक के रूप में इस का इलाज:

सामान्य एसक्यूएल प्रश्न

तो एसक्यूएल कार्यान्वयन है काफी सीधे आगे, क्योंकि SQL'99 WITH RECURSIVE कथन के माध्यम से विनिर्देशन में रैखिक पुनरावर्तन की अनुमति देता है (हालांकि मुझे विश्वास है कि कोई आरडीबीएमएस मानक पूरी तरह कार्यान्वित नहीं करता है)। तो सैद्धांतिक परिप्रेक्ष्य से हम अभी यह कर सकते हैं।

1

उदाहरण में से कोई भी काम मेरे लिए ठीक तो मैं इस तरह यह ठीक करने के बाद:

 
declare 
    results record; 
    entry record; 
    recs record; 
begin 
    for results in select * from project where pid = $1 loop 
     return next results; 
     for recs in select * from project_subtree(results.id) loop 
      return next recs; 
     end loop; 
    end loop; 
    return; 
end; 
10

SQL में एक पुनरावर्ती पूछताछ करने के लिए एक मानक तरीका पुनरावर्ती CTE हैं। PostgreSQL8.4 के बाद से उनका समर्थन करता है। इस लेख

CREATE FUNCTION fn_hierarchy (parent INT) 
RETURNS SETOF example 
AS 
$$ 
     SELECT example 
     FROM example 
     WHERE id = $1 
     UNION ALL 
     SELECT fn_hierarchy(id) 
     FROM example 
     WHERE parentid = $1 
$$ 
LANGUAGE 'sql'; 

SELECT * 
FROM fn_hierarchy(1) 

देखें::

+0

रिकर्सिव सीटीई के लिए +1 जो आजकल सभी प्रमुख डीबीएमएस द्वारा समर्थित है - MySQL और SQLite –

+0

को छोड़कर शायद मैं इसे गलत कर रहा हूं, लेकिन यदि मेरे पास पहले 'चयन' खंड में निर्दिष्ट एक से अधिक फ़ील्ड हैं, उदाहरण के लिए 'चुनें आईडी, नाम ', मुझे 'SELECT fn_hierarchy' पंक्ति पर' प्रत्येक यूनियन क्वेरी में कॉलम की समान संख्या 'त्रुटि होनी चाहिए। मुझे लगता है कि अंतिम 'चयन' में मैं शेष फ़ील्ड प्राप्त करने के लिए 'example' तालिका पर फिर से शामिल हो सकता हूं, लेकिन यह अब और अधिक सुरुचिपूर्ण नहीं है। – poshest

41

यहां कुछ सामान्य तालिका का उपयोग कर एक उदाहरण स्क्रिप्ट है

पहले के संस्करणों में, आप एक पुनरावर्ती सेट लौटने समारोह लिख सकते हैं अभिव्यक्ति:

with recursive sumthis(id, val) as (
    select id, value 
    from example 
    where id = :selectedid 
    union all 
    select C.id, C.value 
    from sumthis P 
    inner join example C on P.id = C.parentid 
) 
select sum(val) from sumthis 

उपरोक्त स्क्रिप्ट sumthis नामक 'वर्चुअल' तालिका बनाता है जिसमें कॉलम id और val हैं। इसे union all के साथ विलय किए गए दो चयनों के परिणामस्वरूप परिभाषित किया गया है।

पहले select रूट (where id = :selectedid) प्राप्त करता है।

दूसरा select पिछले परिणामों के बच्चों का पालन करता है जब तक कि वापस आने के लिए कुछ भी नहीं है।

अंतिम परिणाम तब सामान्य तालिका की तरह संसाधित किया जा सकता है। इस मामले में वैल कॉलम का सारांश दिया जाता है।

+0

यदि मैं आपके कोड को सही ढंग से समझता हूं, तो इसमें चयनित (आईडी, मान) टुपल्स चयनित होते हैं। फिर उन लोगों से जुड़ता है जो Sumthis के एक नए उदाहरण के साथ जुड़ते हैं, जिसमें फिर से वही tuples शामिल हैं। तो यह प्रश्न कभी समाप्त क्यों होगा? मेरी समझ विफलता शायद यह है कि कैसे 'चयनित' सेट किया गया है। या हो सकता है कि बच्चे Sumthis टेबल के लिए मूल्य से आते हैं – lucidbrot

संबंधित मुद्दे