在sql server 2012中使用动态行和属性读取xml

时间:2016-09-24 01:20:56

标签: sql-server xml

我有以下类型的xml

 <root>
    <row1 invoice_number="WEDRT" vendor="Telekm" amount="233" status="1" created_date="42590" />
    <row2 invoice_number="MSFDRT" vendor="ARS" amount="344" status="1" created_date="42955" />
</root>

这个xml是动态生成的。通过动态我的意思是在编写sql代码来解析它时,我不知道有多少行和属性。 可以有多达100,000行和用户想要的属性。我甚至不知道属性的名称。

是否可以通过从此xml中生成以下类型的结果将其放入临时表中?

Invoice_number     Vendor     amount   status    created_Date
WEDRT              TELEKOM     233       1        42590
MSFDRT             ARS         344       1        42955

我试过以下

    DECLARE
    @xml    XML,
    @Columns VARCHAR(MAX)

SET @xml = '
<root>
<row1 invoice_number="WEDRT" vendor="Telekm" amount="233" status="1" created_date="42590" />
<row2 invoice_number="MSFDRT" vendor="ARS" amount="344" status="1" created_date="42955" />
</root>
'
BEGIN   
    SET NOCOUNT ON;

        DECLARE @COUNT INT, @COUNTER INT, @TQUERY   VARCHAR(2000), @SELECT  VARCHAR(MAX), @VALUES   VARCHAR(MAX)
        SELECT * INTO #TEMPTABLE
        FROM(
        SELECT  
            CAST(x.v.query('local-name(.)') AS VARCHAR(100)) As AttributeName,
            v.value('.' , 'VARCHAR(100)') AS Value
            FROM @XML.nodes('//@*') x(v)
            ) A

        SELECT * FROM #TEMPTABLE 

        DROP TABLE #TEMPTABLE
END

它给出了如下表中xml

中2行的结果
AttributeName     Value
invoice_number    WEDRT
vendor            Telekom
amount            233
status            1
created_Date      42590
invoice_number    MSFDRT
vendor            ARS
amount            344
status            1
created_Date      42955

2 个答案:

答案 0 :(得分:4)

我修改了你的查询,希望这有帮助。

DECLARE @xml    XML,
        @Columns VARCHAR(MAX)

SET @xml = '
<root>
<row1 invoice_number="WEDRT" vendor="Telekm" amount="233" status="1" created_date="42590" />
<row2 invoice_number="MSFDRT" vendor="ARS" amount="344" status="1" created_date="42955" />
</root>
'
BEGIN   
    SET NOCOUNT ON;

        DECLARE @COUNT INT, @COUNTER INT, @TQUERY   VARCHAR(2000), @SELECT  VARCHAR(MAX), @VALUES   VARCHAR(MAX)

        SELECT * INTO #TEMPTABLE
        FROM(
            SELECT  CAST(x.v.query('local-name(.)') AS VARCHAR(100)) As AttributeName,
                    x.v.value('.' , 'VARCHAR(100)') AS [Value],
                    CAST(x.v.query('local-name(..)') AS VARCHAR(100)) As RowNumber
            FROM @XML.nodes('//*//@*') x(v)
        ) A

        DECLARE @t TABLE (AttributeName nvarchar(max), r int)
        DECLARE @sql nvarchar(max),
                @col nvarchar(max)

        INSERT INTO @t
        SELECT DISTINCT AttributeName,
                ROW_NUMBER() OVER(PARTITION BY RowNumber ORDER BY RowNumber) as r
        FROM #TEMPTABLE 

        SELECT @col = (
            SELECT ','+QUOTENAME(AttributeName)
            FROM @t
            ORDER BY r
            FOR XML PATH('')
        )


        SELECT @sql = N'
        SELECT *
        FROM #TEMPTABLE t
        PIVOT (
            MAX([Value]) FOR AttributeName IN ('+STUFF(@col,1,1,'')+')
        ) as pvt'

        EXEC sp_executesql @sql

        DROP TABLE #TEMPTABLE
END

输出:

RowNumber   invoice_number  vendor  amount  status  created_date
row1        WEDRT           Telekm  233     1       42590
row2        MSFDRT          ARS     344     1       42955

主要思想是动态调整结果。要删除RowNumber列,您可以使用SELECT '+STUFF(@col,1,1,'')+'代替'SELECT *部分

答案 1 :(得分:0)

你走在正确的轨道上。只需要更改所有元素而不是所有属性:

declare @x xml = '<root>
  <row1 invoice_number="WEDRT" vendor="Telekm" amount="233" status="1" created_date="42590" />
  <row2 invoice_number="MSFDRT" vendor="ARS" amount="344" status="1" created_date="42955" />
</root>';

select t.c.value('local-name(.)', 'sysname') as [NodeName],
    t.c.value('./@invoice_number', 'varchar(50)') as [InvoiceNumber],
    t.c.value('./@vendor', 'varchar(50)') as [Vender],
    t.c.value('./@amount', 'money') as [Amount],
    t.c.value('./@status', 'int') as [Status],
    t.c.value('./@created_date', 'int') as [CreatedDate]
from @x.nodes('/root[1]/*') t(c);

我已将节点名称添加为第一列,以防您可能需要它。如果您没有,请将其从查询中删除。