SQL将XML转换为表

SQL将XML转换为表,xml,sql-server-2005,tsql,xpath,xquery,Xml,Sql Server 2005,Tsql,Xpath,Xquery,在SQL2005中,有没有办法将以下xml转换为表 <root> <r> <data>"col1"</data> <data>"col2"</data> <data>"col3"</data> </r> <r> <data>"data1"</data> <data>""</data&g

在SQL2005中,有没有办法将以下xml转换为表

<root>
  <r>
    <data>"col1"</data>
    <data>"col2"</data>
    <data>"col3"</data>
  </r>
  <r>
    <data>"data1"</data>
    <data>""</data>
    <data>"data3"</data>
  </r>
  <r>
    <data>"data"</data>
    <data>"data"</data>
    <data>"data"</data>
  </r>
</root>
xml可以有不同数量的列,因此解决方案需要考虑这一点


提前谢谢。

我从未做过,但我知道这是可以做到的

看一下本教程,它似乎非常接近您的要求。

列数不可变:SQL通常是固定列

但是,您可以在某种程度上预见到这一点

DECLARE @foo AS xml = '<root>
  <r>
    <data>"col1"</data>
    <data>"col2"</data>
    <data>"col3"</data>
  </r>
  <r>
    <data>"data1"</data>
    <data>""</data>
    <data>"data3"</data>
  </r>
  <r>
    <data>"data"</data>
    <data>"data"</data>
    <data>"data"</data>
  </r>
</root>'

SELECT
   REPLACE(x.item.value('(data)[1]', 'varchar(100)'), '"', '') AS col1,
   REPLACE(x.item.value('(data)[2]', 'varchar(100)'), '"', '') AS col2,
   REPLACE(x.item.value('(data)[3]', 'varchar(100)'), '"', '') AS col3,
   REPLACE(x.item.value('(data)[4]', 'varchar(100)'), '"', '') AS col4,
   REPLACE(x.item.value('(data)[5]', 'varchar(100)'), '"', '') AS col5,
   REPLACE(x.item.value('(data)[6]', 'varchar(100)'), '"', '') AS col6,
   REPLACE(x.item.value('(data)[7]', 'varchar(100)'), '"', '') AS col7,
   REPLACE(x.item.value('(data)[8]', 'varchar(100)'), '"', '') AS col8,
   REPLACE(x.item.value('(data)[9]', 'varchar(100)'), '"', '') AS col9,
   REPLACE(x.item.value('(data)[10]', 'varchar(100)'), '"', '') AS col10
FROM
   @foo.nodes('/root/r') x(item)
/root/r[1]确保获得第一行。row_number枚举在数字和列名之间建立连接的列

@SQL中的查询结果如下:

select 
  replace(r.r.value('data[1]', 'varchar(10)'), '"','') as [col1],
  replace(r.r.value('data[2]', 'varchar(10)'), '"','') as [col2],
  replace(r.r.value('data[3]', 'varchar(10)'), '"','') as [col3] 
from @xml.nodes('/root/r[position()>1]') r(r)
/root/r[position>1]获取除第一个节点外的所有r节点。数据[1]中的1来自行号,[col1]来自相应的列名。quotename将括号[]添加到列别名中。如果没有quotename,此查询可用于SQL注入。替换用于从字符串中删除。它将删除所有出现的,因此,如果您希望成为某个值的一部分,则可以使用substring来删除


我使用varchar10作为列数据的大小。你应该根据需要修改它

这真是太棒了,正是我所需要的。谢谢@Mikael Eriksson的解释。谢谢@AllenG,但是我的数据已经作为nvarcharMax导入到一个表中,从我收集的数据来看,批量最适合从文件系统导入大型XML文件。
;WITH n(i) AS (SELECT 0 UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9),
     o(i) AS (SELECT n3.i * 100 + n2.i * 10 + n1.i FROM n n1, n n2, n n3)
SELECT
   REPLACE(x.item.value('(data)[1]', 'varchar(100)'), '"', '') AS col1,
   REPLACE(x.item.value('(data)[2]', 'varchar(100)'), '"', '') AS col2,
   REPLACE(x.item.value('(data)[3]', 'varchar(100)'), '"', '') AS col3,
   REPLACE(x.item.value('(data)[4]', 'varchar(100)'), '"', '') AS col4,
   REPLACE(x.item.value('(data)[5]', 'varchar(100)'), '"', '') AS col5,
   REPLACE(x.item.value('(data)[6]', 'varchar(100)'), '"', '') AS col6,
   REPLACE(x.item.value('(data)[7]', 'varchar(100)'), '"', '') AS col7,
   REPLACE(x.item.value('(data)[8]', 'varchar(100)'), '"', '') AS col8,
   REPLACE(x.item.value('(data)[9]', 'varchar(100)'), '"', '') AS col9,
   REPLACE(x.item.value('(data)[10]', 'varchar(100)'), '"', '') AS col10,
   o.i
FROM
   o
   CROSS APPLY
   @foo.nodes('/root/r[sql:column("o.i")]') x(item)
declare @xml xml
set @xml = 
'<root>
  <r>
    <data>"col1"</data>
    <data>"col2"</data>
    <data>"col3"</data>
  </r>
  <r>
    <data>"data1"</data>
    <data>""</data>
    <data>"data3"</data>
  </r>
  <r>
    <data>"data"</data>
    <data>"data"</data>
    <data>"data"</data>
  </r>
</root>'

declare @SQL nvarchar(max)
set @SQL = ''

select @SQL = @SQL + ',replace(r.r.value(''data['+
         cast(T.rn as nvarchar(10))+
         ']'', ''varchar(10)''), ''"'','''') as '+
         quotename(replace(T.ColName, '"', '')) 
from
(
  select
    r.r.value('.', 'sysname') as ColName,
    row_number() over(order by (select 1)) as rn
  from @xml.nodes('/root/r[1]/data') r(r)
) as T

set @SQL = 'select '+stuff(@SQL, 1, 1, '')+
        ' from @x.nodes(''/root/r[position()>1]'') r(r)'

exec sp_executesql @SQL, N'@x xml', @x = @xml
select
    r.r.value('.', 'varchar(10)') as ColName,
    row_number() over(order by (select 1)) as rn
  from @xml.nodes('/root/r[1]/data') r(r)
select 
  replace(r.r.value('data[1]', 'varchar(10)'), '"','') as [col1],
  replace(r.r.value('data[2]', 'varchar(10)'), '"','') as [col2],
  replace(r.r.value('data[3]', 'varchar(10)'), '"','') as [col3] 
from @xml.nodes('/root/r[position()>1]') r(r)