2008-10-10 10 views
8

मेरे पास SQL ​​सर्वर में एक सारणी है जिसमें आइटम_आईडी, Item_ParentID की सामान्य वृक्ष संरचना है। मान लीजिए कि मैं पुन: प्रयास करना चाहता हूं और किसी विशेष आइटम_आईडी (किसी भी स्तर पर) के सभी बच्चे को प्राप्त करना चाहता हूं।एसक्यूएल सर्वर में रिकर्सन अच्छा है?

रिकर्सन इस समस्या के लिए एक सहज उम्मीदवार प्रतीत होता है और मैं ऐसा करने के लिए एक SQL सर्वर फ़ंक्शन लिख सकता हूं।

क्या मेरी तालिका में कई रिकॉर्ड हैं यदि यह प्रदर्शन को प्रभावित करेगा? मैं रिकर्सन से कैसे बचूं और बस टेबल से पूछताछ कैसे करूं? कृपया कोई सुझाव दें?

उत्तर

4
नई एमएस एसक्यूएल 2005 के साथ

आप WITH कीवर्ड

बाहर चेक this question और विशेष रूप से this answer इस्तेमाल कर सकते हैं।

ओरेकल के साथ आप पदानुक्रमित प्रश्न (syntax) उत्पन्न करने के लिए CONNECT BY कीवर्ड का उपयोग कर सकते हैं।

MySQL के साथ AFAIK आपको रिकर्सन का उपयोग करना होगा।

वैकल्पिक रूप से आप हमेशा अपने रिकॉर्ड के अभिभावक> बच्चे के सम्बन्ध

0

शायद कुछ और विवरण क्रम में हैं।

यदि आपके पास वर्णन के अनुसार मास्टर-विवरण संबंध हैं, तो क्या आपको एक साधारण जॉइन की आवश्यकता नहीं होगी?

के रूप में:

SELECT 
    SOME_FIELDS 
FROM 
    MASTER_TABLE MT 
,CHILD_TABLE CT 
WHERE CT.PARENT_ID = MT.ITEM_ID 
1

आप एसक्यूएल 2005 का उपयोग कर रहे के लिए एक कैश तालिका का निर्माण कर सकता है?

यदि ऐसा है तो आप इसके लिए सामान्य तालिका अभिव्यक्तियों का उपयोग कर सकते हैं। इन पंक्तियों के साथ कुछ:

; 
with CTE (Some, Columns, ItemId, ParentId) as 
(
    select Some, Columns, ItemId, ParentId 
    from myTable 
    where ItemId = @itemID 
    union all 
    select a.Some, a.Columns, a.ItemId, a.ParentId 
    from myTable as a 
    inner join CTE as b on a.ParentId = b.ItemId 
    where a.ItemId <> b.ItemId 
) 
select * from CTE 
0

आप बच्चों के लिए प्रत्यावर्तन आवश्यकता नहीं होनी चाहिए - आप केवल सीधे नीचे (अर्थात select * from T where ParentId = @parent) स्तर पर देख रहे हैं - आप केवल सभी वंश के लिए प्रत्यावर्तन की जरूरत है।

SQL2005 में आप के साथ वंश प्राप्त कर सकते हैं:

with AllDescendants (ItemId, ItemText) as (
    select t.ItemId, t.ItemText 
     from [TableName] t 
    where t.ItemId = @ancestorId 
    union 
    select sub.ItemId, sub.ItemText 
     from [TableName] sub 
      inner join [TableName] tree 
      on tree.ItemId = sub.ParentItemId 
) 
+0

मुझे लगता है कि उसकी समस्या वह चाहता है "पर है एक विशेष स्तर "। जब तक आप स्तर संख्या संग्रहीत नहीं करते हैं, आप कैसे जानते हैं कि किसी विशेष स्तर पर रूट = स्तर 1 के बिना, रूट = स्तर 2 के बच्चे, बच्चों के बच्चे = स्तर 3, आदि ... नहीं कि रिकर्सन की आवश्यकता है .. लेकिन कई माता-पिता हो सकते हैं। – Cervo

1

समस्या आप प्रत्यावर्तन और प्रदर्शन के साथ सामना करेंगे कितनी बार यह परिणाम देने के recurse करना होगा है। प्रत्येक रिकर्सिव कॉल एक और अलग कॉल है जिसे कुल परिणामों में शामिल किया जाना होगा।

एसक्यूएल में 2K5 आप इस प्रत्यावर्तन को संभालने के लिए एक आम तालिका अभिव्यक्ति का उपयोग कर सकते हैं:

WITH Managers AS 
( 
--initialization 
SELECT EmployeeID, LastName, ReportsTo 
FROM Employees 
WHERE ReportsTo IS NULL 
UNION ALL 
--recursive execution 
SELECT e.employeeID,e.LastName, e.ReportsTo 
FROM Employees e INNER JOIN Managers m 
ON e.ReportsTo = m.employeeID 
) 
SELECT * FROM Managers 

या किसी अन्य समाधान एक एक और तालिका में पदानुक्रम समतल

Employee_Managers
प्रबंधक-करने के लिए है (पी , कर्मचारी तालिका में एफके)
कर्मचारी आईडी (पीके, कर्मचारी तालिका में एफके)

सभी माता-पिता बच्चे के संबंध जहाजों इस तालिका में संग्रहीत किया जाएगा, इसलिए यदि प्रबंधक 1 प्रबंधक 2 कर्मचारी 3 का प्रबंधन करता है प्रबंधन करता है, तालिका दिखाई देगा:

:

ManagerId EmployeeId 
1   2 
1   3 
2   1 

यह पदानुक्रम आसानी से पूछे जाने की अनुमति देता

select * from employee_managers em 
inner join employee e on e.employeeid = em.employeeid and em.managerid = 42 

जो सभी कर्मचारियों प्रबंधक 42 है वापसी होगी उल्टा अधिक से अधिक प्रदर्शन होगा, लेकिन नकारात्मक पक्ष यह पदानुक्रम

2

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

+0

मैंने एक बार ट्रांजैक्ट-एसक्यूएल में एक वीडियो प्लेयर लिखा था! :-P –

+0

आप कर सकते हैं, लेकिन यह निश्चित रूप से पाइथन/रूबी/सी #/जावा/पर्ल/LISP/आदि में एक्सएचटीएमएल पार्सर लिखना बहुत आसान होगा। और प्रदर्शन शायद बेहतर तरीका होगा .... – Cervo

+0

कोई ईमानदार नहीं। यह यहाँ है! http://www.simple-talk.com/sql/t-sql-programming/getting-html-data-workbench/ –

1

जो सेल्को में book (< - अमेज़ॅन से लिंक) विशेष रूप से एसक्यूएल डेटाबेस में वृक्ष संरचनाओं पर है। जबकि आपको अपने मॉडल के लिए रिकर्सन की आवश्यकता होगी और वहां निश्चित रूप से प्रदर्शन के मुद्दों की संभावना होगी, आपकी विशिष्ट समस्या के आधार पर पेड़ संरचना का मॉडल करने के वैकल्पिक तरीके हैं जो रिकर्सन से बच सकते हैं और बेहतर प्रदर्शन दे सकते हैं।

0

आप सभी पर प्रत्यावर्तन की जरूरत नहीं है .... ध्यान दें, मैं कॉलम ItemID और ItemParentID को टाइपिंग में आसानी के लिए बदल ...

 
DECLARE @intLevel INT 
SET @intLevel = 1

INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECT ItemID, ItemParentID, @intLevel WHERE ItemParentID IS NULL

WHILE @intLevel < @TargetLevel BEGIN SET @intLevel = @intLevel + 1 INSERT INTO TempTable(ItemID, ItemParentID, Level) SELECt ItemID, ItemParentID, @intLevel WHERE ItemParentID IN (SELECT ItemID FROM TempTable WHERE Level = @intLevel-1) -- If no rows are inserted then there are no children IF @@ROWCOUNT = 0 BREAK END

SELECt ItemID FROM TempTable WHERE Level = @TargetLevel

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