将多级xml数据转换为Table [MSSQL]?

时间:2014-05-06 06:06:02

标签: sql-server xml select

我在MSSQL 2008中有一个表,其中包含

等数据
  row1 ='<FullData>
    <Employees>
          <Employee ID="001" Name="David" />
          <Employee ID="002" Name="Mike" />
          <Employee ID="003" Name="Alex" />
          <Employee ID="004" Name="Morris" />
    </Employees>
    <Departments>
            <Department ID="01" Name="Food"/>
    </Departments>
    <Groups>
    </Groups>
</FullData>'
row2 =  '<FullData>
    <Employees>
          <Employee ID="005" Name="Fox" />
          <Employee ID="006" Name="Perry" />
          <Employee ID="007" Name="Duals" />
          <Employee ID="008" Name="Harry" />
    </Employees>
    <Departments>
            <Department ID="02" Name="Mobiles"/>
    </Departments>
    <Groups>
            <Group Name="Electronics">
    </Groups>
</FullData>'

和类似的。如何将数据提取到具有此结构的单个表中:

EmployeeID  ||  EmoloyeeName    ||  DepartmentID    ||  DepartmentName  ||  Groups
001,002,..  ||  David,Mike,...  ||  01              ||  Food            ||  
005,006,..  ||  Fox,Perry,..    ||  02              ||  Mobiles         ||  Electronics

有什么建议吗?

UPDATE1

目前我可以从硬编码值中获取值,而不是像

这样的多行中只有一个标签的表格数据
declare @x xml

set @x = '<FullData>
        <Employees>
              <Employee ID="001" Name="David" />
              <Employee ID="002" Name="Mike" />
              <Employee ID="003" Name="Alex" />
              <Employee ID="004" Name="Morris" />
        </Employees>
        <Departments>
                <Department ID="01" Name="Food"/>
        </Departments>
        <Groups>
        </Groups>
    </FullData>'

select emp.e.value('@ID','varchar(50)') as ID, 
        emp.e.value('@Name','varchar(50)') as NAME 
    from @x.nodes('FullData/Employees/Employee') as emp(e)

和输出

001 David
002 Mike
003 Alex
004 Morris

2 个答案:

答案 0 :(得分:1)

尝试以下SQL:

declare @row1 xml;
set @row1 ='<FullData>
    <Employees>
          <Employee ID="001" Name="David" />
          <Employee ID="002" Name="Mike" />
          <Employee ID="003" Name="Alex" />
          <Employee ID="004" Name="Morris" />
    </Employees>
    <Departments>
            <Department ID="01" Name="Food"/>
    </Departments>
    <Groups>
    </Groups>
</FullData>';

declare @row2 xml;
set @row2 =  '<FullData>
    <Employees>
          <Employee ID="005" Name="Fox" />
          <Employee ID="006" Name="Perry" />
          <Employee ID="007" Name="Duals" />
          <Employee ID="008" Name="Harry" />
    </Employees>
    <Departments>
            <Department ID="02" Name="Mobiles"/>
    </Departments>
    <Groups>
            <Group Name="Electronics" />
    </Groups>
</FullData>'
;
with CTE as
(
    select 
     @row1.value('(/FullData/Departments/Department/@ID)[1]','nvarchar(15)') as 'DepartmentId'
     ,emp.ee.value('@ID','nvarchar(5)') as 'EmployeeID'
     ,emp.ee.value('@Name','nvarchar(5)') as 'EmployeeName'
     ,@row1.value('(/FullData/Departments/Department/@Name)[1]','nvarchar(15)') as 'DepartmentName'
     ,@row1.value('(/FullData/Groups/Group/@Name)[1]','nvarchar(15)') as 'Groups'
    from
        @row1.nodes('(/FullData/Employees/Employee)') as emp(ee)
    union all
    select 
     @row2.value('(/FullData/Departments/Department/@ID)[1]','nvarchar(15)') as 'DepartmentId'
     ,emp.ee.value('@ID','nvarchar(5)') as 'EmployeeID'
     ,emp.ee.value('@Name','nvarchar(5)') as 'EmployeeName'
     ,@row2.value('(/FullData/Departments/Department/@Name)[1]','nvarchar(15)') as 'DepartmentName'
     ,@row2.value('(/FullData/Groups/Group/@Name)[1]','nvarchar(15)') as 'Groups'
    from
        @row2.nodes('(/FullData/Employees/Employee)') as emp(ee)
) 
select
    cast(d.EmployeeID as nvarchar(20)) as EmployeeId
    ,cast(d.EmployeeName as nvarchar(25)) as EmployeeName
    ,d.DepartmentId
    ,d.DepartmentName
    ,d.Groups
from
(
select 
    distinct Substring(stuff
    (
        (select ',' + c2.EmployeeId from cte c2 where c2.DepartmentId = c.DepartmentId for xml path(''))
        ,1,0,''
    ),2,len(stuff
                (
                    (select ',' + c2.EmployeeId from cte c2 where c2.DepartmentId = c.DepartmentId for xml path(''))
                    ,1,0,''
                )
            )
    ) as 'EmployeeID'
    , Substring(stuff
    (
        (select ',' + c2.EmployeeName from cte c2 where c2.DepartmentId = c.DepartmentId for xml path(''))
        ,1,0,''
    ),2, len(stuff
                (
                    (select ',' + c2.EmployeeName from cte c2 where c2.DepartmentId = c.DepartmentId for xml path(''))
                    ,1,0,''
                )
            )
    ) as 'EmployeeName'
    , c.DepartmentId
    , c.DepartmentName
    , c.Groups
from CTE c
) d
;

结果:

EmployeeId           EmployeeName              DepartmentId    DepartmentName  Groups
-------------------- ------------------------- --------------- --------------- ---------------
001,002,003,004      David,Mike,Alex,Morri     01              Food            NULL
005,006,007,008      Fox,Perry,Duals,Harry     02              Mobiles         Electronics

答案 1 :(得分:1)

select replace(T.XMLCol.query('data(/FullData/Employees/Employee/@ID)').value('text()[1]', 'nvarchar(max)'), ' ', ',') as EmployeeID,
       replace(T.XMLCol.query('data(/FullData/Employees/Employee/@Name)').value('text()[1]', 'nvarchar(max)'), ' ', ',') as EmployeeName,
       T.XMLCol.value('(/FullData/Departments/Department/@ID)[1]', 'nvarchar(10)') as DepartmentID,
       T.XMLCol.value('(/FullData/Departments/Department/@Name)[1]', 'nvarchar(50)') as DepartmentName,
       T.XMLCol.value('(/FullData/Groups/Group/@Name)[1]', 'nvarchar(50)') as Groups
from T

StackExchange Data Explorer