如何使用动态查询将XML值放入表中?列名称或节点名称未在XML中修复

时间:2017-03-10 06:07:06

标签: sql xml dynamic

DECLARE  @XML1 XML =
'<sender id="1" operation="NewValue" LastName="XYZ" loginId="10029" />
<sender id="2" operation="OldValue" LastName="PQR" loginId="10029" />'

SELECT T.C.value('local-name(.)', 'varchar(50)') AS NodeName,
    T.C.value('(.)[1]', 'varchar(50)') AS NodeValue
FROM @xml1.nodes('//*') AS T(C)

来自OP的评论

又一个例子

DECLARE @xml XML = 
'<row> 
 <operation>NewValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1011</loginId> 
 </row> 
 <row> 
 <operation>OldValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1010</loginId> 
 </row>' 

SELECT T.C.value('local-name(.)', 'varchar(50)') AS NodeName, 
       T.C.value('(.)[1]', 'varchar(50)') AS NodeValue 
FROM @xml.nodes('row/*') AS T(C) 
WHERE T.C.value('(//row/operation/text())[1]', 'VARCHAR(20)') = 'NewValue'

(我希望获得类似此查询的结果,但我的XML格式不同)。

2 个答案:

答案 0 :(得分:1)

这是 - 当然! - 错误的做法。没有 I-read-any-XML-no-matter-what-structure-it-may-have -solution。

请看下面的内容,但是要仔细看看第三个例子:

DECLARE @dummy TABLE(ID INT IDENTITY,Comment VARCHAR(100),YourXML XML);
INSERT INTO @dummy VALUES
 ('Your sample 1'
  ,N'<sender id="1" operation="NewValue" LastName="XYZ" loginId="10029" />
     <sender id="2" operation="OldValue" LastName="PQR" loginId="10029" />')
,('Your sample 2'
  ,N'<row> 
 <operation>NewValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1011</loginId> 
 </row> 
 <row> 
 <operation>OldValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1010</loginId> 
 </row>')
 ,('Show the limits'
  ,N'<row> 
     <element name="test">all have</element>
     <element name="other">the local-name()</element>
     <element name="One more">element</element>
     </row>');

 SELECT ID
       ,Comment
       ,'Element' AS ElementType
       ,t.x.value('local-name(..)','nvarchar(max)') AS ElementName
       ,t.x.value('.','nvarchar(max)') AS ElementValue                                
 FROM @dummy AS d
 CROSS APPLY d.YourXML.nodes(N'//*/text()') AS t(x)
 UNION ALL
 SELECT ID
       ,Comment
       ,'Attribute'
       ,t.a.value('local-name(.)','nvarchar(max)') AS ElementName
       ,t.a.value('.','nvarchar(max)') AS ElementValue                                
 FROM @dummy AS d
 CROSS APPLY d.YourXML.nodes(N'//*/@*') AS t(a)

答案 1 :(得分:1)

Shnugo (在另一篇文章中)建议发布一个Table-Valued-Function,用于解析几乎任何XML结构。我应该添加性能是可敬的(示例1为90 ms),但原生XML会更有效。

原始来源是:http://beyondrelational.com/modules/2/blogs/28/posts/10495/xquery-lab-58-select-from-xml.aspx我只做了一些调整。

示例1

Declare @XML xml ='
<row> 
 <operation>NewValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1011</loginId> 
 </row> 
 <row> 
 <operation>OldValue</operation> 
 <LastName>Gandhi</LastName> 
 <loginId>1010</loginId> 
 </row>' 

Select * from [dbo].[udf-XML-Hier](@XML) Order by R1

<强>返回

enter image description here

示例2

Declare @XML1 xml = '
<sender id="1" operation="NewValue" LastName="XYZ" loginId="10029" />
<sender id="2" operation="OldValue" LastName="PQR" loginId="10029" />
'
Select * from [dbo].[udf-XML-Hier](@XML1) Order By 1

<强>返回

enter image description here

感兴趣的UDF

CREATE FUNCTION [dbo].[udf-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].[udf-XML-Hier](@XML) Order by R1
*/