2010-08-21 12 views
8

मैं एक मेज है कि एक पदानुक्रम परिभाषित करता है:एसक्यूएल क्वेरी: श्रेणीबद्ध संगठित होना

Hierarchy diagram

मैं एक प्रश्न है कि एक ही वापस आ जाएगी लिखना चाहते हैं: इस डेटा के लिए

Create Table [example] (
    id   Integer Not Null Primary Key, 
    parentID Integer  Null, 
    largeData1 nVarChar(max) Null, 
    largeData2 nVarChar(max) Null); 
    -- largeData3...n also exist 

Insert Into [example] (id, parentID, largeData1, largeData2) 
Select 1, null, 'blah blah blah', null   Union 
Select 2, 1, null,    null   Union 
Select 3, 1, 'foo bar foobar', null   Union 
Select 4, 3, null,    'lorem ipsum' Union 
Select 5, 4, null,    null; 

पदानुक्रम आरेख किसी भी दिए गए [आईडी] मूल्य के लिए पंक्ति। पंक्ति में उस पंक्ति की [आईडी] और [parentID] जानकारी होनी चाहिए। इसमें [bigData1 ... n] फ़ील्ड भी होनी चाहिए। हालांकि, यदि कोई बड़ा डेटा फ़ील्ड शून्य है, तो उसे पदानुक्रम को पार करना चाहिए जब तक कि उस फ़ील्ड के लिए एक गैर-शून्य मान न हो। संक्षेप में, कॉलम के सेट के बजाए पंक्तियों के पदानुक्रम को छोड़कर, कोलेसेस फ़ंक्शन की तरह कार्य करना चाहिए।

उदाहरण:

कहाँ [id] = 1:

id:   1 
parentID: null 
largeData1: blah blah blah 
largeData2: null 

कहाँ [id] = 2

id:   1 
parentID: 1 
largeData1: blah blah blah 
largeData2: null 

कहाँ [id] = 3

id:   3 
parentID: 1 
largeData1: foo bar foobar 
largeData2: null 

कहाँ [id] = 4

id:   4 
parentID: 3 
largeData1: foo bar foobar 
largeData2: lorem ipsum 

कहाँ [id] = 5

id:   5 
parentID: 4 
largeData1: foo bar foobar 
largeData2: lorem ipsum 

अब तक, मैं इस है:

Declare @id Integer; Set @id = 5; 

With heirarchy 
    (id, parentID, largeData1, largeData2, [level]) 
As (
    Select id, parentID, largeData1, 
      largeData2, 1 As [level] 
    From example 
    Where id = @id 

    Union All 

    Select parent.id, parent.parentID, 
      parent.largeData1, 
      parent.largeData2, 
      child.[level] + 1 As [level] 
    From example As parent 
    Inner Join heirarchy As child 
     On parent.id = child.parentID) 

Select id, parentID, 
    (Select top 1 largeData1 
    From heirarchy 
    Where largeData1 Is Not Null 
    Order By [level] Asc) As largeData1, 

    (Select top 1 largeData2 
    From heirarchy 
    Where largeData2 Is Not Null 
    Order By [level] Asc) As largeData2 

From example 
Where [id] = @id; 

यह जो परिणाम मैं ढूंढ रहा हूं वह लौटाता है। हालांकि, क्वेरी प्लान के अनुसार, यह प्रत्येक बड़े डेटा क्षेत्र के लिए पदानुक्रम के माध्यम से अलग-अलग पास कर रहा है जिसे मैं वापस खींचता हूं।

मैं इसे और अधिक कुशल कैसे बना सकता हूं?

यह स्पष्ट रूप से एक जटिल समस्या का सरलीकृत संस्करण है। अंतिम क्वेरी एक्सएमएल प्रारूप में डेटा वापस कर देगी, इसलिए फॉर एक्सएमएल क्लॉज से जुड़े किसी भी समाधान पूरी तरह ठीक हैं।

मैं इसके लिए सीएलआर कुल कार्य बना सकता हूं, अगर ऐसा करने में मदद मिलेगी। मैंने अभी तक उस मार्ग की खोज नहीं की है।

उत्तर

6

मैं इस के साथ आया था:

DECLARE @Id int 

SET @Id = 5 


;WITH cte (Id, ParentId, SaveParentId, LargeData1, LargeData2) 
as (-- The "anchor", your target Id 
    select 
     ex.Id 
     ,ex.ParentId 
     ,ex.ParentId SaveParentId -- Not changed throughout the CTE 
     ,ex.LargeData1 
     ,ex.LargeData2 
     from Example ex 
     where ex.Id = @Id 
    union all select 
       cte.Id 
       ,ex.ParentId 
       ,cte.SaveParentId -- Not changed throughout the CTE 
       -- These next are only "reset" if they are null and a not-null 
       -- value was found at this level 
       ,isnull(ex.LargeData1, cte.LargeData2) 
       ,isnull(ex.LargeData2, cte.LargeData2) 
     from Example ex 
     inner join cte 
     on cte.ParentId = ex.Id) 
select 
    Id 
    ,SaveParentId  ParentId 
    ,max(LargeData1) LargeData1 
    ,max(LargeData2) LargeData2 
from cte 
group by Id, SaveParentId 

असल में, अपने लक्ष्य नोड पर शुरू करने और पेड़ पर चलते हैं, अगर और जब वे पाए जाते हैं नहीं-शून्य मान के साथ अपने अशक्त कॉलम की जगह।

(क्षमा करें, लेकिन मैं सप्ताहांत पर एक्सएमएल नहीं करता हूं।)

+0

+1 गैर-शून्य मानों को धक्का देने के लिए +1। लेकिन MAX का उपयोग समस्याग्रस्त हो सकता है। यदि नमूना डेटा की पंक्ति 3 "foo bar bar" के बजाय "afoo bar bar" कहती है, तो @ id = 5 के लिए क्वेरी bigData1 के लिए "blah blah blah" लौटाएगी। – 8kb

+1

जब सीटीई के भीतर "चलना" होता है, यदि किसी दिए गए स्तर पर कॉलम का मान शून्य होता है, तो उसे उस स्तर पर मान के साथ प्रतिस्थापित किया जाता है, अन्यथा इसे अपरिवर्तित छोड़ दिया जाता है। एक पंक्ति प्रति स्तर का उत्पादन होता है। इस प्रकार, जब सीटीई की जाती है, तो सभी पंक्तियों में एक स्तंभ के लिए मूल्य या तो शून्य या पहला मान सामने आएगा। समेकन नल को अनदेखा करते हैं, जिससे अधिकतम (या न्यूनतम) चुनने के लिए केवल एक मान छोड़ दिया जाता है। –

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