使用FOR XML PATH输出多个同级元素

时间:2017-04-12 21:36:58

标签: xml tsql sql-server-2012 for-xml-path select-for-xml

在数据库中,我试图为查询结果中的每一行生成如下所示的XML:

<Message>
<Header>
  <MessageName>MyMessage</MessageName>
  <TimeStamp>2017-03-31T14:32:48</TimeStamp>
  <TrackingNum>1</TrackingNum>
</Header>
<Body>
  <Activity>
    <GUID>SomeGUID</GUID>
    <OrderNum>3242432<OrderNum/>
    <OrderDate>20160331143248</OrderDate>
  </Activity>
</Body>
</Message>

我的查询看起来像这样:

SELECT 
(SELECT DISTINCT top 20
        [GUID],
        OrderNum,
        OrderDate,
    FROM TableA 
    For XML PATH('Activity'), Type
            ) as Body 
    For XML path('Message'),  TYPE

此查询输出<Message><Body>标记中包含的所有行,只包含一个包含所有内容的XML的单元格。我不知道在哪里包含<Header>部分的信息。

上面的查询产生以下内容:不正确/不完整:

 <Message>
    <Body>
        <Activity>
            <GUID>sdlksdkljsdkl</GUID>
            <OrderNum>23423423</OrderNum>
            <OrderDate>20160431143248</OrderDate>
        </Activity>   
        <Activity>
            <GUID>sdfsdfsw4erw</GUID>
            <OrderNum>45560900</OrderNum>
            <OrderDate>20160531143248</OrderDate>
        </Activity>   
        <Activity>
            <GUID>retertertwew</GUID>
            <OrderNum>873409384</OrderNum>
            <OrderDate>20160631143248</OrderDate>
        </Activity>   
    </Body>
</Message>

我们如何在<Body>标记之前添加标题部分,同时将输出拆分为多行?感谢您的任何帮助。

编辑: 模拟Body/Activity元素的数据:

 GUID       OrderNum           OrderDate      
 AAAA       1000               2017-04-13 12:00
 BBBB       2000               2017-04-13 12:00
 CCCC       3000               2017-04-13 12:00

我试图在上面的第一个XML块中获取自己的xml中的每一行。

1 个答案:

答案 0 :(得分:1)

只需将标题添加为 XML类型列

DECLARE @tbl TABLE([GUID] UNIQUEIDENTIFIER,OrderNum BIGINT, OrderDate DATETIME);
INSERT INTO @tbl VALUES(NEWID(),1111111,{ts'2001-01-01 01:00:00'})
                      ,(NEWID(),2222222,{ts'2002-02-02 02:00:00'})
                      ,(NEWID(),3333333,{ts'2003-03-03 03:00:00'});

SELECT 
   (
    SELECT 'SomeMessageName' AS MessageName
          ,GETDATE() AS [TimeStamp]
          ,1 AS TraxingNum
    FOR XML PATH('Header'),TYPE 
   )
  ,(
    SELECT DISTINCT top 20
        [GUID],
        OrderNum,
        OrderDate
    FROM @tbl AS TableA 
    For XML PATH('Activity'), Type
   ) as Body 
For XML path('Message'),TYPE;

结果

<Message>
  <Header>
    <MessageName>SomeMessageName</MessageName>
    <TimeStamp>2017-04-13T10:20:09</TimeStamp>
    <TraxingNum>1</TraxingNum>
  </Header>
  <Body>
    <Activity>
      <GUID>79DE31D2-4727-4880-BB11-72564AE707B0</GUID>
      <OrderNum>3333333</OrderNum>
      <OrderDate>2003-03-03T03:00:00</OrderDate>
    </Activity>
    <Activity>
      <GUID>A9410295-5C78-4EC8-A904-8CB1D10563CF</GUID>
      <OrderNum>2222222</OrderNum>
      <OrderDate>2002-02-02T02:00:00</OrderDate>
    </Activity>
    <Activity>
      <GUID>3192B87D-7C1A-4B95-A477-E10D2FC2845F</GUID>
      <OrderNum>1111111</OrderNum>
      <OrderDate>2001-01-01T01:00:00</OrderDate>
    </Activity>
  </Body>
</Message>

提示

  • 在您的示例中,您的日期就像20160531143248一样。您应始终在 XML中使用ISO8601 。否则当你试着读这篇文章时,你会感到额外的痛苦。
  • 使用TOP而不是ORDER BY是 - 嗯 - 至少是危险的......(你看,我的结果中的顺序不是预期的顺序吗?)

更新

根据您的评论,我认为您正在搜索其中一个(使用上面的模拟表测试它们):

SELECT 
      'SomeMessageName' AS [Header/MessageName]
      ,GETDATE() AS [Header/TimeStamp]
      ,1 AS [Header/TraxingNum]
      ,[GUID] AS [Body/GUID]
      ,OrderNum AS [Body/OrderNum]
      ,OrderDate AS [Body/OrderDate]
FROM @tbl AS TableA
FOR XML PATH('Message'),TYPE;

SELECT 
      (SELECT
      'SomeMessageName' AS [Header/MessageName]
      ,GETDATE() AS [Header/TimeStamp]
      ,1 AS [Header/TraxingNum]
      ,[GUID] AS [Body/GUID]
      ,OrderNum AS [Body/OrderNum]
      ,OrderDate AS [Body/OrderDate]
      FOR XML PATH('Message'),TYPE)
FROM @tbl AS TableA;