Sql server 在sql server 2012中读取具有动态行和属性的xml

Sql server 在sql server 2012中读取具有动态行和属性的xml,sql-server,xml,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

 <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>
我试过以下方法

    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

你在正确的轨道上。您需要做的唯一更改是选择所有元素而不是所有属性:

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);

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

我已修改了您的查询,希望这有帮助

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列,可以使用“选择”+STUFF@col,1,1,+,而不是“选择*零件”

您所说的读取是什么意思?你到底需要什么,以哪种形式?@RogerWolf:对不起,我刚刚更新了预期结果。你有一个很好的工作解决方案,你应该在输出中添加行号,或者在ech发票中添加一些标识,然后PIVOT@gofr1:旋转很好,但正如您所看到的,属性名称在5行之后重复出现。这就是为什么我想我不能透视。我添加了带有动态透视的解决方案,希望这有帮助。谢谢,但在运行时我不知道列的名称,所以我不能硬编码为发票号、供应商等。Beauty,这太棒了。谢谢。是否有可能从最后一个选择中删除rownumber?当然可以!我把这个加在我的答案上,看看它的结尾。我也这么做了。再次感谢。我必须使用临时表而不是表变量,因为xml字符串中的数据将是巨大的。
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);
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