从SQL Server表嵌套为XML

时间:2018-12-06 15:56:53

标签: sql-server xml

这听起来可能很愚蠢(是SQL Server的新功能),但是我正在寻求帮助,指导我如何在SQL Server中编写FOR XML查询以将表导出为非常特定的嵌套格式。我正在将信息导入到的程序需要这种方式,否则它将无法正常工作。

这是我正在使用的表的示例。

Sample Table

下面是我正在寻找的输出。我可以使用此查询生成第一行,但我希望将其嵌套并使其看起来像下面的示例。我不确定如何使XML包装器成为该字段的值。将要使用此功能的最终软件只能使用具有数字的ID,因此这就是为什么我必须以自己的方式对其进行格式化的原因。希望有人可以为此提供指导和指导。

SELECT * 
FROM Tbl_Store
FOR XML Path('Store')

<STORE>
  <box1>
    <item1>
      <size>10</size>
      <weight>15</weight>
    </item1>
    <item2>
      <size>20</size>
      <weight>25</weight>
    </item2>
    <item3>
      <size>30</size>
      <weight>35</weight>
    </item3>
    <item4>
      <size>40</size>
      <weight>45</weight>
    </item4>
    <item5>
      <size>50</size>
      <weight>55</weight>
    </item5>
  </box1>
  <box2>
    <item1>
      <size>10</size>
      <weight>15</weight>
    </item1>
    <item2>
      <size>20</size>
      <weight>25</weight>
    </item2>
    <item3>
      <size>30</size>
      <weight>35</weight>
    </item3>
    <item4>
      <size>40</size>
      <weight>45</weight>
    </item4>
    <item5>
      <size>50</size>
      <weight>55</weight>
    </item5>
  </box2>
</Store>

编辑 最终版本。感谢Shnugo

`SELECT ROW_NUMBER() OVER(ORDER BY Box) AS [@ID]
    ,M.Box as [BoxName]
        ,(
        SELECT m2.Item AS [@ID]
                ,m2.Size AS [size]
                ,m2.[Weight] AS [weight] 
        FROM @mockup m2
        WHERE m2.Box = m.Box
        ORDER BY m2.Item
        FOR XML PATH('item'),TYPE
        )
FROM @mockup m
GROUP BY m.Box 
FOR XML PATH('box'),ROOT('Store')`

1 个答案:

答案 0 :(得分:1)

首先:对于下一个问题:请不要将数据作为图片发布。最好键入[mcve],这没什么好玩的,您可以检查一下我的答案如何在表变量中提供消耗性数据。

第二:名称-编号是一个非常糟糕的主意。人们应该从不做类似

的操作
<item1/>
<item2/>

而且-要回答您的问题-FOR XML不支持,至少不是直接支持。

问题是:任何查询都具有动态元素(数据)和元元素(结构)。您不能动态别名列(换句话说:将数据值用作结果集中的列名称)。

如果您不能避免这样做(我真的建议您重新选择此选项),我们必须使用技巧。

  1. 动态创建整个语句并使用EXEC()
  2. 模拟查询并使用字符串连接:

您的数据作为模型表

DECLARE @mockup TABLE(Box VARCHAR(10),Item INT,Size INT,[Weight] INT);
INSERT INTO @mockup VALUES
 ('box1',1,10,15)
,('box1',2,20,25)
,('box1',3,30,35)
,('box1',4,40,45)
,('box1',5,50,55)
,('box2',1,10,15)
,('box2',2,20,25)
,('box2',3,30,35)
,('box2',4,40,45)
,('box2',5,50,55);

这有效,但是非常丑陋,我现在必须洗手:-)

SELECT CAST(
        CONCAT('<Store>'
             ,(
                SELECT CONCAT('<',Box,'>'
                      ,(
                        SELECT CONCAT('<item',Item,'>'
                              ,'<size>',m2.Size,'</size>'
                              ,'<weight>',m2.[Weight],'</weight>'
                              ,'</item',Item,'>')
                        FROM @mockup m2
                        WHERE m2.Box=m.Box
                        ORDER BY m2.Item
                        FOR XML PATH(''),TYPE).value('.','nvarchar(max)') 

                      ,'</',Box,'>')
                FROM @mockup m
                GROUP BY m.Box
                FOR XML PATH(''),TYPE).value('.','nvarchar(max)') 
             ,'</Store>')
        AS XML);

结果

<Store>
  <box1>
    <item1>
      <size>10</size>
      <weight>15</weight>
    </item1>
    <item2>
      <size>20</size>
      <weight>25</weight>
    </item2>
    <item3>
      <size>30</size>
      <weight>35</weight>
    </item3>
    <item4>
      <size>40</size>
      <weight>45</weight>
    </item4>
    <item5>
      <size>50</size>
      <weight>55</weight>
    </item5>
  </box1>
  <box2>
    <item1>
      <size>10</size>
      <weight>15</weight>
    </item1>
    <item2>
      <size>20</size>
      <weight>25</weight>
    </item2>
    <item3>
      <size>30</size>
      <weight>35</weight>
    </item3>
    <item4>
      <size>40</size>
      <weight>45</weight>
    </item4>
    <item5>
      <size>50</size>
      <weight>55</weight>
    </item5>
  </box2>
</Store>

这就是您应该做的:

SELECT ROW_NUMBER() OVER(ORDER BY Box) AS [@index]
        ,(
        SELECT m2.Item AS [@index]
                ,m2.Size AS [size]
                ,m2.[Weight] AS [weight] 
        FROM @mockup m2
        WHERE m2.Box = m.Box
        ORDER BY m2.Item
        FOR XML PATH('item'),TYPE
        )
FROM @mockup m
GROUP BY m.Box 
FOR XML PATH('box'),ROOT('Store')

结果接近您所需的结果,但设计合理:

<Store>
  <box index="1">
    <item index="1">
      <size>10</size>
      <weight>15</weight>
    </item>
    <item index="2">
      <size>20</size>
      <weight>25</weight>
    </item>
    <item index="3">
      <size>30</size>
      <weight>35</weight>
    </item>
    <item index="4">
      <size>40</size>
      <weight>45</weight>
    </item>
    <item index="5">
      <size>50</size>
      <weight>55</weight>
    </item>
  </box>
  <box index="2">
    <item index="1">
      <size>10</size>
      <weight>15</weight>
    </item>
    <item index="2">
      <size>20</size>
      <weight>25</weight>
    </item>
    <item index="3">
      <size>30</size>
      <weight>35</weight>
    </item>
    <item index="4">
      <size>40</size>
      <weight>45</weight>
    </item>
    <item index="5">
      <size>50</size>
      <weight>55</weight>
    </item>
  </box>
</Store>