|
dev
newsgroups
|
|||||||||||||||||||||||
|
|||||||||||||||||||||||
XML Hierarchy QueryI need help in "flattening" an XML Hierarchy to be used in a downstream process. I am using SQL 2005. Take this XML: <Active> <SummaryGroup> <GroupID>Income</GroupID> <SummaryGroup> <GroupID>Rental</GroupID> <Account> <AccountID>1664</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3072</AccountID> <AllocatedPercent>40</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Misc</GroupID> <SummaryGroup> <GroupID>Interest</GroupID> <Account> <AccountID>2902</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>1709</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Other</GroupID> <Account> <AccountID>2418</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3072</AccountID> <AllocatedPercent>60</AllocatedPercent> </Account> </SummaryGroup> <Account> <AccountID>2831</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> </SummaryGroup> <SummaryGroup> <GroupID>Expenses</GroupID> <Account> <AccountID>2427</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3118</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Gains</GroupID> </SummaryGroup> </Active> You notice that I have 2 kinds of nodes; 1. SummaryGroups that group accounts into contextual buckets and 2. accounts that hold detailed information. There can be any number of SummaryGroups which may or may not contain accounts. Normally every SummaryGroup will have at least one account assigned to it. Each Account has an AllocationPercent to be applied to each SummaryGroup that it belongs. Therefore, each Account can be split up to any number of SummaryGroups as long as the total AllocationPercent adds up to 100%. My question is how do I query this XML string to get the following result below. I am needing to flatten the XML hierarchy into a relational table so I can join it for further downstream processing. SummaryGroup Account EffectiveAllocation Income 1664 100 Income 3072 40 Income 2902 100 Income 1709 100 Income 2418 100 Income 3072 60 Income 2831 100 Rental 1664 100 Rental 3072 40 Misc 2902 100 Misc 1709 100 Misc 2418 100 Misc 3072 60 Misc 2831 100 Interest 2902 100 Interest 1709 100 Other 2418 100 Other 3072 60 Expenses 2427 100 Expenses 3118 100 Thanks in advance for any help. Something like this maybe?
DECLARE @x xml; SET @x = N'<Active> <SummaryGroup> <GroupID>Income</GroupID> <SummaryGroup> <GroupID>Rental</GroupID> <Account> <AccountID>1664</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3072</AccountID> <AllocatedPercent>40</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Misc</GroupID> <SummaryGroup> <GroupID>Interest</GroupID> <Account> <AccountID>2902</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>1709</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Other</GroupID> <Account> <AccountID>2418</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3072</AccountID> <AllocatedPercent>60</AllocatedPercent> </Account> </SummaryGroup> <Account> <AccountID>2831</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> </SummaryGroup> <SummaryGroup> <GroupID>Expenses</GroupID> <Account> <AccountID>2427</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> <Account> <AccountID>3118</AccountID> <AllocatedPercent>100</AllocatedPercent> </Account> </SummaryGroup> <SummaryGroup> <GroupID>Gains</GroupID> </SummaryGroup> </Active>'; SELECT C.value('GroupID[1]', 'nvarchar(100)') AS GroupID, D.value('AccountID[1]', 'int') AS AccountID, D.value('AllocatedPercent[1]', 'int') AS AllocatedPercent FROM @x.nodes('//SummaryGroup') T(C) CROSS APPLY C.nodes('.//Account') U(D) ORDER BY GroupID, AccountID, AllocatedPercent DESC; Show quote "Rob" <rob.clas***@mac.com> wrote in message news:1194304469.351406.212630@57g2000hsv.googlegroups.com... > To all, > I need help in "flattening" an XML Hierarchy to be used in a > downstream process. I am using SQL 2005. > > Take this XML: > > <Active> > <SummaryGroup> > <GroupID>Income</GroupID> > <SummaryGroup> > <GroupID>Rental</GroupID> > <Account> > <AccountID>1664</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3072</AccountID> > <AllocatedPercent>40</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Misc</GroupID> > <SummaryGroup> > <GroupID>Interest</GroupID> > <Account> > <AccountID>2902</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>1709</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Other</GroupID> > <Account> > <AccountID>2418</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3072</AccountID> > <AllocatedPercent>60</AllocatedPercent> > </Account> > </SummaryGroup> > <Account> > <AccountID>2831</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > </SummaryGroup> > <SummaryGroup> > <GroupID>Expenses</GroupID> > <Account> > <AccountID>2427</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3118</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Gains</GroupID> > </SummaryGroup> > </Active> > > You notice that I have 2 kinds of nodes; 1. SummaryGroups that group > accounts into contextual buckets and 2. accounts that hold detailed > information. There can be any number of SummaryGroups which may or > may not contain accounts. Normally every SummaryGroup will have at > least one account assigned to it. Each Account has an > AllocationPercent to be applied to each SummaryGroup that it belongs. > Therefore, each Account can be split up to any number of SummaryGroups > as long as the total AllocationPercent adds up to 100%. > > My question is how do I query this XML string to get the following > result below. I am needing to flatten the XML hierarchy into a > relational table so I can join it for further downstream processing. > > SummaryGroup Account EffectiveAllocation > Income 1664 100 > Income 3072 40 > Income 2902 100 > Income 1709 100 > Income 2418 100 > Income 3072 60 > Income 2831 100 > Rental 1664 100 > Rental 3072 40 > Misc 2902 100 > Misc 1709 100 > Misc 2418 100 > Misc 3072 60 > Misc 2831 100 > Interest 2902 100 > Interest 1709 100 > Other 2418 100 > Other 3072 60 > Expenses 2427 100 > Expenses 3118 100 > > Thanks in advance for any help. >
Show quote
On Nov 5, 7:41 pm, "Mike C#" <x***@xyz.com> wrote: This works as expected. Thank you very much! However, I still don't> Something like this maybe? > > DECLARE @x xml; > SET @x = N'<Active> > <SummaryGroup> > <GroupID>Income</GroupID> > <SummaryGroup> > <GroupID>Rental</GroupID> > <Account> > <AccountID>1664</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3072</AccountID> > <AllocatedPercent>40</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Misc</GroupID> > <SummaryGroup> > <GroupID>Interest</GroupID> > <Account> > <AccountID>2902</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>1709</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Other</GroupID> > <Account> > <AccountID>2418</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3072</AccountID> > <AllocatedPercent>60</AllocatedPercent> > </Account> > </SummaryGroup> > <Account> > <AccountID>2831</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > </SummaryGroup> > <SummaryGroup> > <GroupID>Expenses</GroupID> > <Account> > <AccountID>2427</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > <Account> > <AccountID>3118</AccountID> > <AllocatedPercent>100</AllocatedPercent> > </Account> > </SummaryGroup> > <SummaryGroup> > <GroupID>Gains</GroupID> > </SummaryGroup> > </Active>'; > > SELECT C.value('GroupID[1]', 'nvarchar(100)') AS GroupID, > D.value('AccountID[1]', 'int') AS AccountID, > D.value('AllocatedPercent[1]', 'int') AS AllocatedPercent > FROM @x.nodes('//SummaryGroup') T(C) > CROSS APPLY C.nodes('.//Account') U(D) > ORDER BY GroupID, AccountID, AllocatedPercent DESC; > > "Rob" <rob.clas***@mac.com> wrote in message > > news:1194304469.351406.212630@57g2000hsv.googlegroups.com... > > > > > To all, > > I need help in "flattening" an XML Hierarchy to be used in a > > downstream process. I am using SQL 2005. > > > Take this XML: > > > <Active> > > <SummaryGroup> > > <GroupID>Income</GroupID> > > <SummaryGroup> > > <GroupID>Rental</GroupID> > > <Account> > > <AccountID>1664</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > <Account> > > <AccountID>3072</AccountID> > > <AllocatedPercent>40</AllocatedPercent> > > </Account> > > </SummaryGroup> > > <SummaryGroup> > > <GroupID>Misc</GroupID> > > <SummaryGroup> > > <GroupID>Interest</GroupID> > > <Account> > > <AccountID>2902</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > <Account> > > <AccountID>1709</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > </SummaryGroup> > > <SummaryGroup> > > <GroupID>Other</GroupID> > > <Account> > > <AccountID>2418</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > <Account> > > <AccountID>3072</AccountID> > > <AllocatedPercent>60</AllocatedPercent> > > </Account> > > </SummaryGroup> > > <Account> > > <AccountID>2831</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > </SummaryGroup> > > </SummaryGroup> > > <SummaryGroup> > > <GroupID>Expenses</GroupID> > > <Account> > > <AccountID>2427</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > <Account> > > <AccountID>3118</AccountID> > > <AllocatedPercent>100</AllocatedPercent> > > </Account> > > </SummaryGroup> > > <SummaryGroup> > > <GroupID>Gains</GroupID> > > </SummaryGroup> > > </Active> > > > You notice that I have 2 kinds of nodes; 1. SummaryGroups that group > > accounts into contextual buckets and 2. accounts that hold detailed > > information. There can be any number of SummaryGroups which may or > > may not contain accounts. Normally every SummaryGroup will have at > > least one account assigned to it. Each Account has an > > AllocationPercent to be applied to each SummaryGroup that it belongs. > > Therefore, each Account can be split up to any number of SummaryGroups > > as long as the total AllocationPercent adds up to 100%. > > > My question is how do I query this XML string to get the following > > result below. I am needing to flatten the XML hierarchy into a > > relational table so I can join it for further downstream processing. > > > SummaryGroup Account EffectiveAllocation > > Income 1664 100 > > Income 3072 40 > > Income 2902 100 > > Income 1709 100 > > Income 2418 100 > > Income 3072 60 > > Income 2831 100 > > Rental 1664 100 > > Rental 3072 40 > > Misc 2902 100 > > Misc 1709 100 > > Misc 2418 100 > > Misc 3072 60 > > Misc 2831 100 > > Interest 2902 100 > > Interest 1709 100 > > Other 2418 100 > > Other 3072 60 > > Expenses 2427 100 > > Expenses 3118 100 > > > Thanks in advance for any help.- Hide quoted text - > > - Show quoted text - quite understand what and how it is doing it though. Could you put a little verbage around what piece of the statement is doing what. This way I can learn a little bit more and hopefully be a bit more self reliant. Thanks again for you help and I hope you have the time and energy to explain more of the details. "Rob" <rob.clas***@mac.com> wrote in message No problem. The first part just declares an XML variable and assigns the news:1194368321.039184.159900@19g2000hsx.googlegroups.com... > This works as expected. Thank you very much! However, I still don't > quite understand what and how it is doing it though. Could you put a > little verbage around what piece of the statement is doing what. This > way I can learn a little bit more and hopefully be a bit more self > reliant. > > Thanks again for you help and I hope you have the time and energy to > explain more of the details. > XML document you provided to it. The interesting stuff is the use of the XML nodes() method and the path expressions. I'll start from the bottom of the SELECT query and work my way up to the top. The ORDER BY clause of the query is just to order the results to make it more readable, so we can ignore that part. The FROM clause is interesting. I'm using the @x.nodes('//SummaryGroup') clause to shred the relevant nodes into relational rows. The //SummaryGroup path expression matches the SummaryGroup node anywhere it appears in your XML document. The nodes method requires that you alias the result with a table and column name (in this case I chose T for the table and C for the column name... T(C)). FROM @x.nodes('//SummaryGroup') T(C) The CROSS APPLY oeprator is also new to SQL Server 2005. It allows you to apply a function to the results of another function in the FROM clause. In this case I'm taking each row of the results of the @x.nodes(...) method and re-shredding it with the C.nodes('//Account') method. The './/Account' path expression starts with the context node (in this case the SummaryGroup node for the current row in C represented by '.'), and returns all Account nodes that occur anywhere within it (//Account). CROSS APPLY C.nodes('.//Account') U(D) The SELECT clause uses the value() method to grab individual values from the shredded XML. Based on your requirements the GroupID had to come from within the SummaryGroup node, while the other values had to come from within the Account nodes inside the SummaryGroup nodes. The [1] is a numeric predicate to restrict the result of the path expression to a singleton atomic value (required by the value() method). SELECT C.value('GroupID[1]', 'nvarchar(100)') AS GroupID, D.value('AccountID[1]', 'int') AS AccountID, D.value('AllocatedPercent[1]', 'int') AS AllocatedPercent That's it, hope it's helpful. If you're diving into XQuery for the first time, I'd locate a tutorial on path expressions to start out with. W3schools.com (I think that's the website) should have some tutorials and reference material you might find helpful. |
|||||||||||||||||||||||