我有一个存储过程,它弹出两列。一个是ID,另一列是该ID的高度复杂的XML格式。我的要求是将此XML转换为表格式。 XML具有300个节点和子节点。结构如下:
<Main>
<Version>1.0</Version>
<CId>459876569</CId>
<Overview>
<Type>Y</Type>
<CreateDate>20180505</CreateDate>
<PlanType>A</PlanType>
<EffectiveDate>20171201</EffectiveDate>
<EndDate>20181130</EndDate>
<Comments>No other comments</Comments>
</Overview>
<EssentialInfo>
<ContactI>
<LastName>Doe</LastName>
<MiddleName>A</MiddleName>
<FirstName>John</FirstName>
<DateOfBirth>19500808</DateOfBirth>
<Gender>F</Gender>
<Address>
<AddressLine1>dfsfsdf</AddressLine1>
<AddressLine2>dsfsdfa</AddressLine2>
<City>gdfgdfg</City>
</Address>
<HomePhone>98745632148</HomePhone>
</Contact>
</EssentialInfo>
</Main>
我知道OPENXML方法,但是命名300列会使它很乏味。还有其他解决方法吗?
我正在尝试实现Workflow suggestion - XML & SQL的此功能,为此,我正在尝试将巨大的XML转换为SQL表
答案 0 :(得分:2)
如果作为辅助函数开放给TVF,并且假定XML将被透视为一个记录。
很显然,完全声明的SQL性能更高。
示例
Declare @XML xml ='
<Main>
<Version>1.0</Version>
<CId>459876569</CId>
<Overview>
<Type>Y</Type>
<CreateDate>20180505</CreateDate>
<PlanType>A</PlanType>
<EffectiveDate>20171201</EffectiveDate>
<EndDate>20181130</EndDate>
<Comments>No other comments</Comments>
</Overview>
<EssentialInfo>
<Contact>
<LastName>Doe</LastName>
<MiddleName>A</MiddleName>
<FirstName>John</FirstName>
<DateOfBirth>19500808</DateOfBirth>
<Gender>F</Gender>
<Address>
<AddressLine1>dfsfsdf</AddressLine1>
<AddressLine2>dsfsdfa</AddressLine2>
<City>gdfgdfg</City>
</Address>
<HomePhone>98745632148</HomePhone>
</Contact>
</EssentialInfo>
</Main>
'
Select * Into #Temp from [dbo].[tvf-XML-Hier](@XML) Order by R1
Declare @SQL varchar(max) = '
Select *
From (
Select Item = concat(Element,IIF(Attribute='''','''',''_''+Attribute))
,Value
From #Temp
) A
Pivot (max([Value]) For [Item] in (' + Stuff((Select ','+QuoteName(concat(Element,IIF(Attribute='','','_'+Attribute)))
From #Temp
Where Value is not null
Order by R1
For XML Path('')),1,1,'') + ') ) p'
Exec(@SQL);
返回
感兴趣的TVF
ALTER FUNCTION [dbo].[tvf-XML-Hier](@XML xml)
Returns Table
As Return
with cte0 as (
Select Lvl = 1
,ID = Cast(1 as int)
,Pt = Cast(NULL as int)
,Element = x.value('local-name(.)','varchar(150)')
,Attribute = cast('' as varchar(150))
,Value = x.value('text()[1]','varchar(max)')
,XPath = cast(concat(x.value('local-name(.)','varchar(max)'),'[' ,cast(Row_Number() Over(Order By (Select 1)) as int),']') as varchar(max))
,Seq = cast(1000000+Row_Number() over(Order By (Select 1)) as varchar(max))
,AttData = x.query('.')
,XMLData = x.query('*')
From @XML.nodes('/*') a(x)
Union All
Select Lvl = p.Lvl + 1
,ID = Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10
,Pt = p.ID
,Element = c.value('local-name(.)','varchar(150)')
,Attribute = cast('' as varchar(150))
,Value = cast( c.value('text()[1]','varchar(max)') as varchar(max) )
,XPath = cast(concat(p.XPath,'/',c.value('local-name(.)','varchar(max)'),'[',cast(Row_Number() Over(PARTITION BY c.value('local-name(.)','varchar(max)') Order By (Select 1)) as int),']') as varchar(max) )
,Seq = cast(concat(p.Seq,' ',10000000+Cast( (Lvl + 1) * 1024 + (Row_Number() Over(Order By (Select 1)) * 2) as int ) * 10) as varchar(max))
,AttData = c.query('.')
,XMLData = c.query('*')
From cte0 p
Cross Apply p.XMLData.nodes('*') b(c)
)
, cte1 as (
Select R1 = Row_Number() over (Order By Seq),A.*
From (
Select Lvl,ID,Pt,Element,Attribute,Value,XPath,Seq From cte0
Union All
Select Lvl = p.Lvl+1
,ID = p.ID + Row_Number() over (Order By (Select NULL))
,Pt = p.ID
,Element = p.Element
,Attribute = x.value('local-name(.)','varchar(150)')
,Value = x.value('.','varchar(max)')
,XPath = p.XPath + '/@' + x.value('local-name(.)','varchar(max)')
,Seq = cast(concat(p.Seq,' ',10000000+p.ID + Row_Number() over (Order By (Select NULL)) ) as varchar(max))
From cte0 p
Cross Apply AttData.nodes('/*/@*') a(x)
) A
)
Select A.R1
,R2 = IsNull((Select max(R1) From cte1 Where Seq Like A.Seq+'%'),A.R1)
,A.Lvl
,A.ID
,A.Pt
,A.Element
,A.Attribute
,A.XPath
,Title = Replicate('|---',Lvl-1)+Element+IIF(Attribute='','','@'+Attribute)
,A.Value
From cte1 A
/*
Source: http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx
Declare @XML xml='<person><firstname preferred="Annie" nickname="BeBe">Annabelle</firstname><lastname>Smith</lastname></person>'
Select * from [dbo].[tvf-XML-Hier](@XML) Order by R1
*/
如果有助于可视化,TVF将返回
很显然,如果不需要所有列,可以将其精简