【问题标题】:How to select multiple rows as single XML column with T-SQL and XQuery如何使用 T-SQL 和 XQuery 选择多行作为单个 XML 列
【发布时间】:2016-12-20 21:22:39
【问题描述】:

鉴于以下数据集,我希望将数据按 Name 分组,但将 RoleIDRoleNamePermissionIDPermissionName 的值放在一起作为单个 XML 值:

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

【问题讨论】:

    标签: tsql xquery


    【解决方案1】:

    我将您的数据集用作 CTE (foo),并通过使用嵌套选择和分组方式获得了您所需的结果。我使用“名称”作为用户键,因为您的示例数据中没有用户 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
    

    【讨论】:

    • AFAICT 如果您指定 FOR XML PATH('Role'), ROOT('Roles'), TYPE',则不需要强制转换为 XML。参考:TYPE Directive in FOR XML Queries通过指定 TYPE 指令请求将 FOR XML 查询的结果作为 xml 数据类型返回
    • PS:您可以在RexTester 进行快速测试。查看我的个人资料了解更多有趣的内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2017-06-05
    相关资源
    最近更新 更多