有关通过SQL语句/过程生成的多层XML的问题

时间:2019-06-03 20:22:56

标签: sql sql-server xml

我正在研究如何获取一条SQL语句(很好地从存储过程中)以及如何从查询结果中生成XML输出。我在XML中获得的输出如下所示:

<Application>
    <Device AppEnabled="true" AsOf="06/03/2019 16:01:58 UTC" Name="MachineName">
        <Groups>
            <Group Name="Administrators" ReportChanges="true">
                <Members>
                    <Member Name="AdminUser1" />
                    <Member Name="AdminUser2" />
                    <Member Name="AdminUser3" />
                    <Member Name="AdminUser4" />
                </Members>
            </Group>
            <Group Name="Normal Users" ReportChanges="true">
                <Members>
                    <Member Name="NormalUser1" />
                    <Member Name="NormalUser2" />
                </Members>
            </Group>
        </Groups>
    </Device>
</Application>

“ AdminUser1”和“ NormalUser1”都来自两个单独的查询。为了简单起见,我们将查询看起来如下:

SELECT UserName 
FROM AdminUsers 
WHERE Computer = 'ComputerName'

SELECT UserName 
FROM NormalUsers 
WHERE Computer = 'ComputerName'

理想情况下,我们将'ComputerName'作为参数。 “ AsOf”将是当前时间戳。 “ AppEnabled”将来自另一个查询,该查询检查此计算机是否设置为或多或少使用该应用程序。我想我可以查找一下并将值存储在变量中。

另一个项目是'reportchanges = true'实际上来自另一个查询,该查询查找要添加到'Group Name = xxx'项目中的任何项目。因此,存在一个表,其中包含要包含在该标头中的设置和值。当前只有一个附加项目(即ReportChanges = true),但可能有多个项目。该查询看起来像这样:

SELECT XMLSetting, XMLValue 
FROM XMLItems;

我一直在对查询中的“ FOR XML”进行修改,该查询可以正确设置“成员/成员”组的格式,但是如何在所有其他层中添加?

1 个答案:

答案 0 :(得分:1)

您的格式将需要很多嵌套级别。像这样尝试(下一次,请像我在此处使用DDL和INSERT一样以易消耗的格式提供示例数据):

DECLARE @AdminUsers TABLE(UserName VARCHAR(100),Computer VARCHAR(100));
DECLARE @NormalUsers TABLE(UserName VARCHAR(100),Computer VARCHAR(100));

INSERT INTO @AdminUsers VALUES('Admin1','blah')
                             ,('Admin2','blah')
                             ,('Admin3','Other');
INSERT INTO @NormalUsers VALUES('user1','blah')
                              ,('user2','blah')
                              ,('user3','Other');

DECLARE @ComputerName VARCHAR(100)='blah';

SELECT 'true' AS [Device/@AppEnabled]
      ,GETDATE() AS [Device/@AsOf]
      ,@ComputerName AS [Device/@MachineName]
      ,(
        SELECT
           (
                SELECT 'Administrators' AS [@Name]
                      ,'true' AS [@ReportChanges]
                      ,(
                        SELECT UserName AS [Member/@name]
                        FROM @AdminUsers 
                        WHERE Computer=@ComputerName 
                        FOR XML PATH(''),ROOT('Members'),TYPE
                       ) AS [*]
                FOR XML PATH('Group'),TYPE
            ) AS [*]
          ,(
                SELECT 'Normal Users' AS [@Name]
                      ,'true' AS [@ReportChanges]
                      ,(
                        SELECT UserName AS [Member/@name]
                        FROM @NormalUsers 
                        WHERE Computer=@ComputerName 
                        FOR XML PATH(''),ROOT('Members'),TYPE
                       ) AS [*]
                FOR XML PATH('Group'),TYPE
            ) AS [*]
        FOR XML PATH(''),TYPE
       ) AS [Device/Groups]
FOR XML PATH('Application'),TYPE;

结果

<Application>
  <Device AppEnabled="true" AsOf="2019-06-04T10:10:50.160" MachineName="blah">
    <Groups>
      <Group Name="Administrators" ReportChanges="true">
        <Members>
          <Member name="Admin1" />
          <Member name="Admin2" />
        </Members>
      </Group>
      <Group Name="Normal Users" ReportChanges="true">
        <Members>
          <Member name="user1" />
          <Member name="user2" />
        </Members>
      </Group>
    </Groups>
  </Device>
</Application>

更新

具有相同结果的另一种方法

WITH Groups AS
(
    SELECT 'Administrators' AS GroupName
    UNION ALL
    SELECT 'Normal Users'
)
SELECT 'true' AS [@AppEnabled]
      ,GETDATE() AS [@AsOf]
      ,@ComputerName AS [@MachineName]
      ,(
        SELECT GroupName AS [@name]
              ,'true' AS [@ReportChanges]
              ,(
                SELECT names.*
                FROM
                (
                    SELECT UserName AS [@Name] FROM @AdminUsers WHERE GroupName='Administrators' AND Computer=@ComputerName 
                    UNION ALL
                    SELECT UserName AS [@Name] FROM @NormalUsers WHERE GroupName='Normal Users' AND Computer=@ComputerName
                ) names
                FOR XML PATH('Member'),TYPE
               ) AS Members
        FROM Groups
        FOR XML PATH('Group'),TYPE
       ) AS Groups
FOR XML PATH('Device'),ROOT('Application');