2016-12-05 36 views
3

考虑下面的数据集一个XML列,我想Name分组的数据,但RoleIDRoleNamePermissionIDPermissionName值被放在一起作为一个单XML值:如何选择多行与T-SQL和XQuery

Name   RoleID  RoleName  PermissionID PermissionName 
--------------- ----------- ------------- ------------ --------------- 
User 1   2   Super User 1   View 
User 1   2   Super User 2   Create 
User 1   2   Super User 3   Edit 
User 1   2   Super User 4   Delete 
User 1   3   Report User 17   Execute 

所以,输出我试图去,应该是这个样子:

Name  Roles 
------------ ------------------------------------------------------- 
User 1  <Roles> 
       <Role id="2" name="Super User"> 
        <Permissions> 
         <Permission id="1" name="View" /> 
         <Permission id="2" name="Create" /> 
         <Permission id="3" name="Edit" /> 
         <Permission id="4" name="Delete" /> 
        </Permissions> 
       </Role> 
       <Role id="3" name="Report User"> 
        <Permissions> 
         <Permission id="17" name="Execute" /> 
        </Permissions> 
       </Role> 
      </Roles> 

我曾尝试以下,但它会创建一个Role行在数据集中的每个条目:

SELECT 
     U.[ID] as [Name] 
    , CONVERT(xml, (
     SELECT 
      R.[ID] as '@id' 
      , R.[Name] as '@name' 
      , CONVERT(xml, (
       SELECT 
        P.[ID] as '@id' 
       , P.[Name] as '@name' 
       FOR XML PATH('Permission') 
      )) as [Permissions] 
     FOR XML PATH('Role'), ROOT('Roles') 
    )) as [Roles] 
FROM User U 
    LEFT JOIN UserRoles UR ON 
     U.[ID] = UR.[UserID] 
    LEFT JOIN Role R ON 
     UR.[RoleID] = R.[ID] 
    LEFT JOIN RolePermissions RP ON 
     R.[ID] = RP.[RoleID] 
    LEFT JOIN Permission P ON 
     RP.[PermissionID] = P.[ID] 
WHERE 
    U.[ID] = 1234 

回答

1

我用了你的数据集,而不是作为一个CTE(富),并通过使用嵌套选择和集团通过获得您想要的结果。我使用“Name”作为用户密钥,因为您的示例数据中没有用户ID,但您应该能够使其与查询一起工作。

with foo as 
(
select 
* 
from 
(values 
('User 1','2',' Super User','1','View') 
,('User 1','2',' Super User','2','Create') 
,('User 1','2',' Super User','3','Edit') 
,('User 1','2',' Super User','4','Delete') 
,('User 1','3',' Report User','17',' Execute') 
) foo(Name,RoleID,RoleName,PermissionID,PermissionName) 
) 

select 
    Name, 
    cast((
    SELECT 
     B.RoleID as '@id' 
     ,B.RoleName as '@name' 
     ,cast((select PermissionID as '@id',PermissionName as '@name' 
     from Foo C 
     where c.RoleID=b.RoleID 
       and c.Name=a.Name 
     for xml path('Permission') 
    ) as xml) Permissions 
    FROM foo B 
    group by 
     B.RoleID 
     ,B.RoleName 
    for xml path('Role'),root('Roles') 
    ) as xml) Roles 
from 
foo a 
group by Name 

我没有测试过下面的查询,但它应该是非常接近的东西在你的表工作:

select 
    U.ID as [Name], 
    cast((
    SELECT 
     R.[ID] as '@id' 
     , R.[Name] as '@name' 
     ,cast(
     (select 
      P.[ID] as '@id' 
      , P.[Name] as '@name' 
     from RolePermissions RP 
      LEFT JOIN Permission P ON 
      RP.[PermissionID] = P.[ID] 
     where R.[ID] = RP.[RoleID] 
     for xml path('Permission') 
    ) as xml) [Permissions] 
    FROM UserRoles UR 
     Left Join Role R 
     ON UR.[RoleID] = R.[ID] 
     where U.[ID] = UR.[UserID] 
    group by 
     R.[ID] 
     ,R.[Name] 
    for xml path('Role'),root('Roles') 
    ) as xml) [Roles] 
from 
User U 
group by ID 
WHERE 
    U.[ID] = 1234 
+1

AFAICT演员阵容到XML是没有必要的,如果你指定'FOR XML PATH('角色'),ROOT('角色'),TYPE''。参考:[FOR XML查询中的TYPE指令](https://msdn.microsoft.com/zh-cn/library/ms190025.aspx):*请求通过指定FOR XML查询的结果作为xml数据类型返回TYPE指令*。 –

+0

PS:您可以在[RexTester](http://rextester.com/l/sql_server_online_compiler)进行快速测试。查看我的个人资料以获取更有趣的内容 –